A programmable layer for BitGraph

Player

Player evaluates a rule over a set of BitGraph proofs and returns TRUE, FALSE or UNDETERMINED, offline, with the same verdict on any machine. For anyone who needs a decision about the order of recorded files that a stranger can replay.

What you need

  • RuntimeNode.js. The package runs with npx; nothing else is installed.
  • Package@mikeargento/bitgraph-player 0.15.0, MIT-licensed.
  • A bundleA directory, .tar or .tar.gz holding proof.json files, or Frame files from the earlier single fused form (<name>.bitgraph-fuse.json), with the files they are about and, for earlier proofs, the Ethereum anchors that floor them (a proof with a Base floor signs its floor block itself). Player does not yet read the current bitgraph-export/1 file; that support is pending.
  • A ruleA JSON file naming each file by its fingerprint (SHA-256 digest) and stating a claim about their order. init writes the skeleton for you.

You are done when npx @mikeargento/bitgraph-player rule.json bundle/ writes a verdict, exits 0, 1 or 2, and the verdict names the evidence each answer rests on; and when running it again over the same rule bytes and the same bundle produces a byte-identical verdict.

What it is

BitGraph records. Player evaluates.

A BitGraph recording establishes that particular bytes occupied a particular causal position. Player takes a set of those recordings, applies a rule to them, and produces a verdict: TRUE, FALSE, or UNDETERMINED.

Anyone with the same rule and the same evidence can reproduce that verdict themselves, on their own machine, offline. No network, no clock, no account, and no trust in whoever ran Player first.

A purchase order was recorded. Later, a delivery was recorded. Later still, an approval was recorded. No declared cancellation was recorded before the approval. A Player rule can express exactly that claim and determine whether the BitGraph evidence supports it.

A rule names the artifacts it cares about and states a claim about their causal order:

  • the delivery was recorded after the purchase order
  • the approval was recorded after the delivery
  • no declared cancellation occurred before the approval

Player evaluates that claim against the recordings in a proof bundle and writes a verdict that shows its work, step by step, including the evidence each answer rests on.

Player evaluates; it does not enforce. No field in a rule can cause an external action. If a system pays an invoice after a TRUE verdict, that system sits above Player. Player only determines what follows from the rule and the evidence it was given.

A rule

rule.json
{
  "rule": "bitgraph-player/1",
  "id": "po-release-payment",
  "cast": {
    "purchase_order": { "digest": "sha256:…", "means": "PO-4471" },
    "delivery":       { "digest": "sha256:…" },
    "approval":       { "digest": "sha256:…" },
    "cancellation":   { "digest": "sha256:…", "optional": true }
  },
  "world": "closed",
  "requires": { "ordering": "assumption-dependent" },
  "claim": { "all": [
    { "exists": "purchase_order" },
    { "after":  ["delivery", "purchase_order"] },
    { "after":  ["approval", "delivery"] },
    { "not": { "before": ["cancellation", "approval"] } }
  ]},
  "then": { "label": "release_payment" }
}

Cast and claim

Every rule separates two kinds of facts.

cast contains facts supplied by the rule author: which digest represents the purchase order, which digest represents the delivery, which occurrence is intended, or who a signer is said to represent.

claim contains only what Player is allowed to derive from BitGraph evidence: whether a recording exists, whether one recording came before or after another, or whether the available evidence fails to establish an answer.

The verdict never mixes the two. A reader can always see which facts came from BitGraph and which were asserted by the person who wrote the rule. That separation is the trust boundary.

The security floor

Every rule must declare the limits under which its claim is allowed to be evaluated.

world: "closed" scopes negative claims to the artifacts declared in the rule. For example, this rule does not claim that no cancellation exists anywhere. It claims only that no cancellation represented by the declared cancellation role was established before the approval. Negative claims never extend beyond the evidence the rule declares.

requires.ordering is the rule’s security floor. It specifies what kind of ordering evidence the author is willing to accept. hash-linked accepts conclusions supported by hash-linked ordering evidence alone. assumption-dependent also permits ordering conclusions that rely on accepted BitGraph assumptions, including counter order and the Ethereum anchor floors of earlier proofs.

There is no default. A rule that does not declare its ordering floor does not parse, because that floor is part of the rule’s own security policy. The tool must not choose it for the author.

Three answers, not two

Every claim evaluates to one of three answers.

  • TRUEThe evidence supports the claim at or above the rule’s declared security floor.
  • FALSEThe evidence refutes the claim.
  • UNDETERMINEDThe available evidence does not decide.

UNDETERMINED is the correct answer when, for example:

  • the evidence does not establish the order of two recordings
  • the same digest was recorded more than once and nothing selects the intended occurrence
  • the available ordering evidence falls below the rule’s declared security floor

A two-valued evaluator would have to launder those cases into TRUE or FALSE and would therefore be wrong on some inputs. Player refuses to invent certainty. When the evidence cannot decide the claim, the verdict is UNDETERMINED and states why.

Run it

With Node.js installed, evaluate a rule against a BitGraph proof bundle. A bundle may be a directory, .tar, or .tar.gz. Discovery is by schema shape, not by filename, so any layout holding proof.json files works. A Frame file (<name>.bitgraph-fuse.json, from the earlier single fused form) is read as a proof carrier. An export/1 file is not read yet: take the proof object out of it and give Player that as proof.json until export support lands.

Shell
npx @mikeargento/bitgraph-player rule.json bundle/ > verdict.json

To begin a rule from the files themselves, init hashes the files and writes a skeleton with the cast filled in:

Shell
npx @mikeargento/bitgraph-player init po.pdf delivery.jpg approval.pdf --out rule.json

It deliberately leaves requires.ordering unset. The security floor belongs to the rule author. Player will not choose it.

To read an export without a rule, check prints a bitgraph-check/1 report: a three-valued line per check for each recording, with its floor (the anchor floor, on earlier proofs). A recording marked fused adds a fused line (the commitment check, over the fused bytes or the original), a fused floor (on earlier proofs, the last anchored block before its position) and a fused span (reserved position to commit position).

Shell
npx @mikeargento/bitgraph-player check export/

The process exit code is the verdict summary, so another program can gate on it directly:

CodeMeaning
0TRUE: the evidence supports the claim at or above the declared floor
1FALSE: the evidence refutes the claim
2UNDETERMINED: the evidence does not decide
3Error: bad rule file, unreadable bundle, or invalid usage

Same evidence, same verdict

Two runs of the same rule bytes over the same bundle contents produce byte-identical verdicts, on any machine, at any later time. The verdict carries no clock reading, filesystem path, or machine-local state. Every ordering conclusion identifies the evidence it rests on and whether that conclusion depends on an assumption.

Nothing in a check reaches the network. The bundle carries the proof, the file and, for an earlier proof, the Ethereum anchor that gives its position a floor (a tree/1 proof, like any proof with a Base floor, signs its floor block itself); the verifier carries its own copy of the code and the enclave measurement it will accept. Pull the cable and the verdict is the same, which is the whole design: a recording has to stay checkable years from now, by someone who should not have to trust a server to tell them what their own bytes say.

That is also why the check does not live on this site. A page loaded from bitgraph.ing is trusted exactly as far as bitgraph.ing is, and we are the party being checked. A signed package you install once, pinned to a version, is a smaller thing to trust. The PCR0 it enforces is reproducible from published inputs, so you can confirm it names the enclave we say it does.

Auditing a decision stops being a matter of reading a report someone wrote and becomes replaying the decision yourself.

There is a loose architectural analogy to Ethereum: BitGraph provides the recorded substrate, while Player provides deterministic evaluation over it. The difference is deliberate. The EVM’s value is that participants agree on execution. Player’s value is that anyone can independently reproduce the evaluation. Player does not make BitGraph an authority. It makes claims over BitGraph evidence reproducible.

Specification

The semantics are specified precisely enough to reimplement. Player’s own SPEC.md (the rule language, the three answers, the verdict) is normative for Player. The proofs it reads are specified by the protocol’s SPEC.md. The published package is the MIT-licensed reference implementation, built on the same audit pipeline used to inspect a BitGraph bundle by hand. A conforming Player in any language must reach the same verdict from the same rule and the same evidence.

Where next