The native output of vero run (chapter 8.3): newline-delimited JSON, one event per line, written
as the run happens and flushed line by line, so a run that is killed leaves a file whose every
complete line parses. vero run --events <path> writes it; --events - writes it to stdout and
moves the human report to stderr. The file is a contract: its shape changes only with its version.
Carries all seven terminal states without the lossy mapping JUnit forces. JUnit and TAP are
exports; this is the record.
Rules
- Every line is one JSON object with the four common fields below.
vero.events/v1 changes only additively: a new event type or a new field may appear; no
field is removed, renamed or retyped. A change that needs any of those is vero.events/v2.
Consumers must ignore fields and types they do not know.
- Durations are milliseconds as JSON numbers. A timing phase that did not happen on a request
(dns, connect or tls on a reused connection) is the string
"n/a", never 0 (chapter 4.3).
- Bodies are cut at
--events-body-cap bytes (default 65536) and the event says so with
bodyTruncated: true. Nothing is cut silently. Bytes that are not UTF-8 become U+FFFD.
- Secrets are scrubbed by value from every line before it is written (C04).
- Each
--repeat iteration is its own run with its own runId, from run.start to run.end.
- Order:
run.start, then per task task.start, per step step.start, the step's request
events (or attempt events for a waitFor, or one query event for a sql step, or one fixture event for a fixture step, or one exec event for an exec step, or one ws event for a ws step, or one grpc event for a grpc step), its assert events, step.end, then task.end; tasks that never started have only a
task.end; finally run.end. Events of tasks running at the same time interleave.
The tables below are checked by internal/report/contract_test.go against the Go types in
internal/report/events.go: a field in one and not the other fails the build.
Common fields
| Field |
Type |
Present |
schema |
string, always vero.events/v1 |
always |
ts |
string, RFC 3339 UTC with milliseconds |
always |
runId |
string, the run's id |
always |
type |
string, one of the types below |
always |
run.start
| Field |
Type |
Present |
plan |
string, metadata.name |
always, may be empty |
planFile |
string, the plan's path as given |
always |
version |
string, vero's module version and Go toolchain |
always |
jobs |
number, --jobs |
always |
flags |
object, every flag set on the command line, name to value |
always, may be empty |
runtimes |
array of {name, binary, path, version}, each script runtime the plan uses as found on PATH (F01) |
when the plan has script steps |
task.start
| Field |
Type |
Present |
task |
string |
always |
section |
string, tasks or finally |
always |
holds |
array of strings, resources the task holds |
when it holds any |
step.start
| Field |
Type |
Present |
task |
string |
always |
step |
number, 1-based |
always |
kind |
string: http, graphql, ws, grpc, sql, exec, waitFor, script, fixture |
always |
request
One per HTTP exchange; a repeat emits one per request, in send order for serial and completion
order for parallel.
| Field |
Type |
Present |
task |
string |
always |
step |
number, 1-based |
always |
index |
number, 0-based position among the step's requests |
always |
method |
string |
always |
url |
string |
always |
status |
number, 0 when no response arrived |
always |
proto |
string, the protocol that answered: HTTP/1.1 or HTTP/2.0 |
when a response arrived |
requestHeaders |
array of {name, value}, names lower case, sorted |
always |
requestBody |
string; a file sent by bodyFile or a multipart part appears as «file <path>, <size> bytes, sha256 <hex>» in place of its bytes |
always, may be empty |
responseHeaders |
array of {name, value} |
always, empty when no response |
responseBody |
string, decompressed |
always, may be empty |
bodyTruncated |
boolean, true when either body was cut here or by the driver's cap |
always |
wireSize |
number, response body bytes as received (compressed if compressed) |
always |
size |
number, response body bytes after decompression |
always |
duration |
object: dns, connect, tls, ttfb, total, each a number or "n/a" |
always |
connection |
string, new or reused |
always |
error |
string, the transport error |
when the exchange failed |
timedOut |
boolean |
when the deadline fired |
phase |
string, the phase in progress when the deadline fired: dns, connect, tls, write, ttfb, body |
when timed out |
redirects |
array of {method, url, status}, the hops before this response |
when followRedirects is on and there were hops; each hop also has a request event of its own, just before |
retried |
boolean, true for an attempt that failed in a way the step's retry covers and was sent again |
when true |
assert
| Field |
Type |
Present |
task |
string |
always |
step |
number, 1-based |
always |
index |
number, 1-based position in the step's assert list |
always |
expr |
string, as written in the plan |
always |
location |
string, file:line |
always |
outcome |
string: held, failed, n/a, error |
always |
error |
string |
when outcome is error |
values |
array of {path, value}, every path the assertion read and its value |
when not held |
detail |
array of strings, the failure explanation (elements that broke an all) |
when not held |
query
One per sql step (D01): the query as written, its bound arguments, and how many rows came back.
The rows themselves are in the assert events' values when an assertion fails.
| Field |
Type |
Present |
task |
string |
always |
step |
number, 1-based |
always |
connection |
string, the connection's name in the plan |
always |
query |
string, the literal query |
always |
args |
array of strings, the rendered, bound arguments |
always, may be empty |
rows |
number, rows returned; 0 also when the query failed |
always |
columns |
array of strings |
when the query ran |
error |
string |
when the query failed |
timedOut |
boolean |
when the step's deadline fired |
durationMs |
number |
always |
fixture
One per fixture step: the statement as written, its bound arguments, and whether the write
committed. A fixture step writes reference data through a connection declared writes: true, and
this event is the label on that write: a reader of the log can see every row a run put in a
database, and through which connection.
| Field |
Type |
Present |
task |
string |
always |
step |
number, 1-based |
always |
connection |
string, the connection's name in the plan |
always |
statement |
string, the literal statement |
always |
args |
array of strings, the rendered, bound arguments |
always, may be empty |
rowsAffected |
number; 0 when it rolled back |
always |
committed |
boolean; false means nothing was written |
always |
error |
string |
when the statement or the commit failed |
timedOut |
boolean |
when the step's deadline fired |
durationMs |
number |
always |
grpc
One per grpc step (B12, B13), after the call returned or the step ended.
| Field |
Type |
Present |
task |
string |
always |
step |
number, 1-based |
always |
target |
string |
always |
method |
string, /package.Service/Method |
always |
message |
string, the request as JSON |
always; empty for a method that takes a stream |
sent |
array of strings, each request as JSON, in order |
for a method that takes a stream |
code |
string, the status name; empty when no server answered (error says why) or vero stopped the stream (stopped) |
always |
statusMessage |
string |
always, may be empty |
response |
string, the response as JSON with exact numbers |
always, empty unless the code is OK and the method returns one message |
received |
array of {atMs, body}, each streamed response and when it arrived after the call started |
when a server stream sent any |
stopped |
boolean, true when vero ended the stream at expect.count or expect.timeout |
when true |
headers |
array of {name, value} |
always |
trailers |
array of {name, value} |
always |
bodyTruncated |
boolean, true when any message or response was cut at --events-body-cap |
always |
durationMs |
number |
always |
firstMs |
number, when the first streamed response arrived |
when a server stream sent any |
error |
string |
when no server answered or the step timed out |
timedOut |
boolean |
when the step's deadline or the run's fired |
ws
One per ws step (B11), after the socket closed or the step ended.
| Field |
Type |
Present |
task |
string |
always |
step |
number, 1-based |
always |
url |
string |
always |
status |
number, the upgrade response's status; 101 on success, 0 when none came |
always |
sent |
array of strings, the messages sent, in order |
always |
received |
array of {atMs, body}, each message and when it arrived after the upgrade |
always |
closed |
object {code, reason}, the server's close frame |
when the server closed |
bodyTruncated |
boolean, true when a message was cut at --events-body-cap |
always |
duration |
object: connect, tls, upgrade, first, total, each a number or "n/a" |
always |
error |
string |
when the step errored or timed out |
timedOut |
boolean |
when the step's deadline or the run's fired |
exec
One per exec step (D04): the process that ran and what it printed.
| Field |
Type |
Present |
task |
string |
always |
step |
number, 1-based |
always |
argv |
array of strings, the rendered command |
always |
dir |
string, the working directory |
always |
exitCode |
number, or null when the process was killed or never started (never -1) |
always |
stdout |
string, as captured, then cut at --events-body-cap |
always, may be empty |
stderr |
string, likewise |
always, may be empty |
stdoutBytes |
number, bytes the process wrote to stdout, kept or not |
always |
stderrBytes |
number, likewise for stderr |
always |
stdoutTruncated |
boolean, stdout passed the step's maxOutput and the rest was discarded |
always |
stderrTruncated |
boolean, likewise |
always |
bodyTruncated |
boolean, stdout or stderr was cut here by the event body cap |
always |
error |
string, why it did not start or finish |
when it did not |
timedOut |
boolean |
when the deadline killed the group |
signal |
string, SIGTERM or SIGKILL, the last signal sent to the group |
when timed out |
durationMs |
number |
always |
script
One per event a script step's child wrote to stdout, and one per line of its stderr, emitted as
they arrive (F02). Secret values are scrubbed like every other line. The protocol is
docs/content/contracts/script-v1.md.
| Field |
Type |
Present |
task |
string |
always |
step |
number, 1-based |
always |
kind |
string: log, step, result, or stderr for a stderr line |
always |
level |
string |
for log and stderr |
msg |
string |
for log and stderr |
name |
string |
for step |
status |
string |
for step |
durationMs |
number |
for step |
ok |
boolean |
for result |
attempt
One per try of a waitFor step (chapter 7.3), in order. A wait never produces request or
assert events: its tries are not requests the plan counts and its until is not an assertion.
| Field |
Type |
Present |
task |
string |
always |
step |
number, 1-based |
always |
attempt |
number, 1-based |
always |
status |
number, 0 when the try got no response |
always |
error |
string, the transport error, such as connection refused |
when the try failed |
ready |
boolean, whether until held on this try |
always |
durationMs |
number, this try's total time |
always |
step.end
| Field |
Type |
Present |
task |
string |
always |
step |
number, 1-based |
always |
state |
string, the step's state: passed, failed, errored, timed_out |
always |
reason |
string |
when not passed |
durationMs |
number |
always |
attempts |
number, requests a waitFor made |
on waitFor steps (C05) |
waitedMs |
number, how long a waitFor waited |
on waitFor steps (C05) |
requests |
number, requests the step put on the wire, every retry and redirect hop included |
when the step sent any |
retries |
number, attempts that were retried |
when any were |
task.end
| Field |
Type |
Present |
task |
string |
always |
section |
string, tasks or finally |
always |
state |
string, one of the seven: passed, failed, errored, timed_out, skipped, blocked, not_run |
always |
reason |
string |
when not passed |
blockedBy |
string, the upstream task that blocked it |
when blocked |
durationMs |
number, 0 for a task that never started |
always |
hosts |
array of strings, the host:port of every request the task sent, ws upgrades and grpc targets included (E02's heuristic reads these with the task.start and task.end times) |
when it sent any |
unverified |
boolean, the task passed only as passed (unverified): a script step returned ok with no step events (F02) |
when true |
repeat.summary
One per task after the last run of vero run --repeat N (E01), when N is more than 1. It belongs
to the whole invocation rather than one run: runId is the last run's, and runIds lists them all.
| Field |
Type |
Present |
task |
string |
always |
runs |
number, N |
always |
runIds |
array of strings, every run's id in order |
always |
counts |
object, all seven states to how many runs ended the task in each |
always |
flaky |
boolean, the task did not end in the same state every run |
always |
varied |
array of {step, index, expr, outcomes, observed}: each assertion whose outcome varied, outcomes mapping held/failed/n/a/error to counts, observed a list of {path, values: [{value, count}], other} with at most 10 distinct values per path, most frequent first, the rest counted in other |
when flaky and some assertion varied |
compare.summary
One per task after vero run --repeat N --compare-jobs (E02, C13), after the last run at the
higher job count. Like repeat.summary it belongs to the whole invocation: runId is the last
run's. It holds what the terminal's --jobs 1 versus --jobs N table printed.
| Field |
Type |
Present |
task |
string |
always |
jobs |
number, the higher job count |
always |
serialRuns |
number, runs at --jobs 1 |
always |
serialPassed |
number, of those the task passed |
always |
wideRuns |
number, runs at --jobs N |
always |
widePassed |
number, of those the task passed |
always |
verdict |
string: stable, flaky-wide-only (passed every run at --jobs 1, not at --jobs N) or flaky-both |
always |
hint |
string, the hint as the terminal printed it, lines separated by \n |
when the verdict has one |
run.end
| Field |
Type |
Present |
counts |
object, all seven states to their counts, zeros included, finally tasks included |
always |
teardown |
object, the finally tasks alone, all seven states to their counts (C10) |
when the plan has finally tasks |
tasks |
number |
always |
unverified |
number, passed tasks that were passed (unverified); they are in counts.passed too |
when not zero |
exitCode |
number, the exit code this run calls for (chapter 8.4) |
always |
wallMs |
number |
always |