Worlds
The state inside a sandbox: rows, files, armed failures and the clock.
A world is the state a twin holds: its rows, its files, its armed failures, and the clock it shares with the other twins in the sandbox. It is real tables in a real database, readable and writable over HTTP while the sandbox runs.
A fresh sandbox is not empty. Every twin boots with a default world already seeded, so your first test runs against a customer who exists, a card that declines and a list long enough to paginate, with no setup call in front of it.
What is already there
Seven people are seeded into a twin’s default world, and each one carries a situation you would otherwise have to build: a working case, no money, a blocked account, a brand new account, an unusual format, a failure in the history, and enough rows to force a second page.
Dates are anchored to when the sandbox started, so last month’s invoice is actually last month on every boot.
In the Stripe twin they land like this. Look ids up at runtime with
veris sandbox data get stripe customers, or GET /veris/data?entity_type=customers; the email address is the stable handle.
| Person | Already true in the Stripe twin | What you can test without seeding |
|---|---|---|
Amara Oseiamara.osei@example.com | Two succeeded payment intents, and a visa ending 4242 valid to 12/2030 | The path that has to work |
Ben Kowalskiben.kowalski@example.com | A card ending 9995 that declines for insufficient funds | A 402 whose decline_code is insufficient_funds |
Carmen Reyescarmen.reyes@example.com | A card ending 4212 that expired 03/2024 | A 402 whose code is expired_card, at charge time rather than when the card was attached |
Devi Sharmadevi.sharma@example.com | A customer with no payment method, no payment intent and no charge | Empty lists, and the branch that runs for a customer with no history |
Eiji Nakamuraeiji.nakamura@example.com | One payment intent for 3800 in jpy, a currency with no decimal places | Amount handling that assumes two decimal places |
Fatima Al-Aminfatima.alamin@example.com | A card ending 5126 whose refunds fail | A refund created succeeded that turns failed later, with failure_reason expired_or_canceled_card |
Gus Thorntongus.thornton@example.com | 11 payment intents against a default page size of 10 | has_more: true, and the second trip round your pagination loop |
Every twin covers those same seven situations in its own vendor’s shapes. Where a vendor has no way to hold one, that twin leaves it out rather than inventing it: Stripe has no way to block a person, so Carmen’s block sits on her card instead.
A few twins seed fewer than seven people, and the Postgres twin seeds none,
because the tables in it are yours. veris sandbox data get <twin>, or GET /veris/data on that twin’s control URL, shows what it actually holds.
The same person in every twin
Amara Osei is one person across the sandbox, appearing in each vendor’s own shape: a Stripe customer, a GitHub user, a HubSpot contact, a Slack member. Same name, same employer, same story. That is what makes a cross-service test possible: a test that charges a customer and then posts about it is talking about one person, not two records that happen to match.
Her situation follows her too, in each vendor’s own terms. Carmen Reyes holds the blocked case everywhere: her Stripe card expired 03/2024, her GitHub account is suspended, her HubSpot contact is archived, her Slack member is deactivated.
One person is not one email address. Commerce twins such as Stripe, HubSpot and
QuickBooks carry the personal address, amara.osei@example.com. Workspace and
identity twins such as GitHub, Slack and Jira carry the work address,
amara.osei@lakeshore-outfitters.example. Match on the address the twin you are
querying uses; a lookup keyed on one address across both finds nothing in half
the sandbox.
Reading it
veris sandbox data get <twin> # every table in that twin, with counts
veris sandbox data get <twin> customers # a page of one table's rows<twin> is a name from veris sandbox services list. $CONTROL_URL is that
twin’s control URL, printed by veris sandbox services get <twin>.
curl "$CONTROL_URL/veris/data"{ "counts": { "customers": 7, "payment_methods": 9, "payment_intents": 17, "charges": 16 } }counts names every table in that twin. To read the rows of one:
curl "$CONTROL_URL/veris/data?entity_type=customers"Rows come back newest first, 100 at a time over HTTP and 20 at a time in the
CLI, with total, limit and offset for the rest; --limit, --offset and
--all page through them. Table and column definitions come from
veris sandbox data schema <twin>, or /veris/schema over HTTP, written for
whoever is operating the sandbox. Read them rather than guessing field names.
The console’s Data tab browses the same thing with row counts and column descriptions, which is easier when you do not yet know what you are looking for.
Ids are stable within a sandbox, and stable across sandboxes only when the clock is frozen. Read them at runtime rather than pasting one from a previous sandbox into a test.