Core concepts
Environment, sandbox, twin, world, receipt: the five terms the rest of these docs use.
Five terms run through the rest of these docs. An environment names a set of twins, a sandbox is one running copy of that environment, each twin holds a world, and a run through the proxy prints a receipt.
Environment
An environment is a named list of twins. You define it once and it outlives every
run, so a name is the only thing a run needs. One comes from
veris env create checkout --services stripe,postgres, recorded in
.veris/twin.yaml and committed with the repository; veris env list shows the
ones a project has, and veris env use picks the one this folder runs against.
veris services is the catalog of every twin an environment can include.
Sandbox
A sandbox is one isolated running copy of an environment, ready in seconds. It
has a time to live and is deleted when that expires whether or not anything is
using it: --ttl, then the environment’s ttl_minutes in .veris/twin.yaml,
then the control plane’s own default — the CLI carries none of its own. For a
veris run --fresh sandbox that lifetime is a backstop for teardown never
running, since --fresh deletes its sandbox when the run ends. One
environment has many sandboxes: veris up starts one for this folder and
veris down deletes it, and veris run --fresh does both around a single run.
veris sandbox reset restores every twin to its boot seed, so the same test runs
again from the same starting state.
Twin
A twin is one simulated vendor inside a sandbox. It holds state: a write persists,
a later read reflects it, and an operation that is invalid for the current state
is refused the way the vendor refuses it. Your code reaches a twin without
changing, keeping the same hostname, the same credential and the same SDK. Where
an address does move it moves through a variable your code already reads, never
through an edit: setup’s direct tier points each vendor base URL at the sandbox
that way, and a twin with no hostname to intercept — a data plane such as a
database — has its URL handed to your command by veris run itself, under the
variable that twin publishes. Either way the path under test is the shipped one.
Twins covers what each one reproduces, down to error
envelopes and scopes.
World
A world is what a twin holds: its rows, its files, its armed failures, and the
clock it shares with the other twins in the same sandbox. A fresh sandbox is not
empty, so your first test needs no seeding. The same person is the same person in
every twin in the sandbox, which is what makes a test that spans two vendors
possible. Read and write a world while the sandbox runs: veris sandbox data for
rows, veris sandbox clock for time, or the twin’s own control_url over HTTP,
which veris sandbox services get prints. Worlds
covers seeding, faults, time and reset.
Receipt
A receipt is what the sandbox received during a run, printed when the run ends:
veris: the sandbox received 14 request(s), counted per twin. It is what
veris run reports, so it is the container tier’s record; the direct tier puts
no proxy in front of the command and its evidence is the twin’s own trace
instead. Test output is
identical whether or not your suite reached its dependency, so a
veris run --fresh, which deploys the sandbox it runs against, fails on an empty
receipt even when every test passed. A service requirement fails a run the same
way wherever it came from — --require-service on the command line, or
proxy.require_service recorded in .veris/twin.yaml, which setup writes, so a
repository setup wired already carries one. --require-service stripe:2 asserts a
minimum count for a named twin, and where a requirement is in play it is what
decides the run; attached to a sandbox that was already up, an empty receipt with
none in play is a warning. Running tests covers veris run
and what an empty receipt means.