Implementation Test Pipeline
Preserve the Go command as the authority and the byte streams as evidence. Treat decoded events and live output as downstream interpretations that may add detail but may not rewrite execution history.
Execute and capture
- Accept the Go executable, working directory, environment policy, and argv as
separate values. Preserve every Go argument after
--exactly and avoid a shell. - Prepare secure evidence files before starting the child. Create rather than follow evidence destinations and refuse unsafe managed paths.
- Tee stdout bytes to
test_output.jsonlbefore protocol framing. Tee stderr bytes tostderr.logbefore diagnostic or console processing. Propagate write failures to orchestration without discarding child status. - Stream incrementally with bounded buffers and backpressure. Do not hold the complete run in memory merely to decode or display it.
- Wait for the child and drain owned streams. Preserve numeric exit status, signal termination, start failure, wait failure, and cancellation as distinct evidence.
- After raw files close, persist a bounded
run.jsonthat binds the status to the exact event, stderr, and optional coverage bytes by size and SHA-256. Record whether the child started, whether exit status is known, whether capture completed, the monotonic child span asduration_nswhen available, and every fatal run-integrity issue. Encode one stricttested/run/v1document no larger than 1 MiB; reject duplicate JSON members at every depth, unknown fields, trailing JSON values, inconsistent cancellation/timing state, duplicate or unmanaged bindings, and a missingtest_output.jsonlbinding. Accept only interrupt→130 and terminated→143 for signal cancellation. Permit at most the three canonical evidence names and sort bindings lexically when encoding.
Frame a tolerant bounded protocol
Decode a tagged union with these semantic variants:
TestEventcarries Gotest2jsonpackage/test actions, timestamps, elapsed values, and output.- Go 1.25
attrand Go 1.26artifactsare knownTestEventactions. Decode and retain theirKey/ValueorPathfields and exact raw record. Bind each record to the source package or active test occurrence and retain its source sequence for deterministic, occurrence-aware projections. BuildEventcarries non-test build or tool diagnostics that remain relevant even when no package/test terminal action appears.
Accept chunk boundaries at arbitrary byte positions. Tolerate CRLF, blank
records, a final record without a newline, and non-JSON build/diagnostic text.
Apply --max-event-bytes before allocating or decoding a complete record.
Default the limit to 16 MiB, require a nonzero override to be at least 1 KiB,
and treat zero as an explicit opt-out. When a record exceeds an active bound,
discard or spool only according to the documented bounded algorithm, emit one
bounded diagnostic for that record, and resume at the next framing boundary.
Within an otherwise bounded record, permit at most 64 fields unknown to the
selected schema and 64 KiB total decoded unknown-field names plus exact
retained JSON values. Reject duplicate decoded object members at every retained
depth, including escaped-equivalent names. Treat extension exhaustion and
duplicate members as malformed semantic evidence without changing raw capture.
Never substitute tolerance for truth:
- Preserve every input byte in raw evidence even when decoding rejects it.
- Associate malformed, unknown, oversized, and truncated data with diagnostics rather than inventing a test action.
- Bound diagnostic count and retained text as well as frame size so adversarial output cannot cause a second memory expansion.
- Close or finish the stream explicitly so an unterminated final record is handled once and active semantic state can be finalized.
Aggregate occurrences
Model a test occurrence independently from its display name. Use package, logical test name, and a monotonically assigned occurrence ordinal as the stable identity. Allocate a new ordinal whenever a new run begins after a terminal occurrence with the same package and name; do not merge retries or repeated invocations.
Apply --max-test-output-bytes independently to the output retained for each
normalized test occurrence, package, build, and unattributed-output scope.
Retain a deterministic prefix or other documented bounded projection plus the
original and retained byte counts and an explicit truncation marker. Default
to 1 MiB for each scope, require nonzero overrides to be at least 1 KiB, and
interpret zero as unlimited. Never apply this bound to test_output.jsonl.
Also enforce run-wide retained-output, normalized-entry, and normalized-string budgets. The defaults are 64 MiB, 1,000,000 entries, and 128 MiB, respectively; zero explicitly disables any bound. Count packages, occurrences, builds, metadata records, unknown-action summaries, retained output chunks, and dynamically retained identity/metadata strings so many individually small records cannot bypass aggregate memory policy. Keep output text under its separate output budgets. When semantic entries or strings must be dropped, retain raw evidence, emit one bounded integrity diagnostic, and make the derived result incomplete rather than silently undercounting it.
Apply package and test transitions in event order:
- Record
runas the start of one occurrence. - Record output with source order and owning package/test when known.
- Recognize a Go benchmark result containing only its benchmark name and
iteration count as terminal benchmark evidence. Go omits the metric pairs
when the measured
ns/opis exactly zero. Reassemble the canonical, literal-tab benchmark-name prefix with subsequent same-package, same-test-scope output portions through their line ending whentest2jsonexposes one result as multiple events. Attribute the prefix immediately to a provisional benchmark occurrence and account every portion under the normal output budgets in source order. Bound aggregate assembly bytes and fragments; retain an explicitly incomplete provisional occurrence when its scope changes, an unscoped event makes continuity unverifiable, its completion is malformed or missing, or capacity is exhausted. Resolve an already observed exact benchmark identity before interpreting a trailing numeric-Nas a CPU suffix and falling back to its base identity. Preserve an occurrence that already had independent terminalbenchevidence. Capacity exhaustion also makes the derived result incomplete and emits one bounded diagnostic. Preserve every original chunk on a successfully assembled occurrence. Repeated result lines must still become distinct occurrences. Keep independent terminalbenchevidence authoritative whether it arrives before or after an interrupted partial result line. Whentest2jsonemits a complete package-scoped result before test-scoped benchmark logs and the terminalbenchaction, accept exactly one matching terminal action as corroborating the already completed occurrence; a duplicate remains an integrity violation.test2jsoncan also omitrunwhen a benchmark report and its test-scoped log output precedebench,fail, orskip. Allow those three terminal actions to finish an inferred benchmark evidence occurrence with nonempty test-scoped output; keep ordinary orphan terminals and a benchmarkpassinvalid. - Accept
pass,fail, andskipas terminal event outcomes. - Preserve package terminal state separately from child process state.
- Preserve build failures even if no corresponding package event completes.
- Treat contradictory or impossible transitions as diagnostics and keep the strongest observed failure evidence.
At EOF, parser termination, cancellation, or child termination, finalize every
active package and test as incomplete. Do not count incomplete as pass, fail,
or skip, and do not omit it from machine reports.
Return immutable, deterministically sorted snapshots. Keep analyzer mutation private so renderers cannot change aggregation state.
Represent time honestly
Prefer a valid terminal event Elapsed value as the measured duration for that
package or occurrence. When elapsed is absent but compatible event timestamps
bound a lifecycle, compute an estimate and mark its quality as estimated.
When neither exists, leave duration absent.
Keep these values distinct:
- child wall-clock run span;
- event-reported measured duration;
- timestamp-derived estimated duration;
- no duration evidence.
Do not sum overlapping test durations to claim wall-clock time. Renderers must carry duration quality into JSON/JUnit metadata and human labels where the difference matters.
Cancel the complete process tree
Give the child a process-group or platform-equivalent ownership boundary. On context cancellation:
- mark the run cancellation cause;
- request graceful termination for the owned process tree;
- continue draining stdout and stderr;
- after a bounded grace interval, force termination of remaining descendants;
- wait, reap, close streams, and finalize active results as incomplete.
Use a two-second graceful interval when no internal override is configured. Bound post-exit pipe draining and forced-termination waits as well as the first signal interval.
Handle races between natural exit and cancellation idempotently. Never signal a reused process identifier after ownership has ended, and never return while an owned child or pipe goroutine can still mutate artifacts.
Use a non-reaping exit observer where the platform provides one. Commit the
wait-state transition that disables process-tree signaling before Cmd.Wait
releases the stable child identity. On Windows, observe the process handle
becoming signaled before reaping and retain an assigned Job Object through
post-wait cleanup. If the observer fails, fail closed by terminating the owned
tree before disabling signaling and reaping, and bound that fallback reap in
case termination also fails. Never pass a reaped numeric PID to taskkill. If
Job Object assignment fails, preserve the ownership error and make only a
bounded pre-reap taskkill attempt while the original process handle still
reserves the leader PID. After reaping, use only the stable Job Object and
preserve any ownership or cleanup error.
Treat test-helper control files as bounded protocols. Publish content-bearing records completely to a same-directory temporary file and atomically rename them into view; require an explicit completion delimiter and retry absent, empty, or unterminated observations until a deadline. Use existence-only markers only when their contents are irrelevant and install the guarded state before creating them. On setup failure, cancel and join the helper, and disable numeric-PID cleanup immediately after observing that the process is gone. Have the parent signal a blocking helper and bound its wait; do not let a helper race asynchronous self-signal delivery against a fallback exit.
Classify programmatic cancellation, deadline expiry, SIGINT, and SIGTERM
separately. Preserve the observed child status, but project cancellation to the
documented shell result (130 for programmatic/deadline/SIGINT and 143 for
SIGTERM). Apply cancellation precedence through coverage and report generation,
not only while the Go child is running, and remove or withhold the manifest
when cancellation prevents a coherent publication.
Apply failure precedence
Preserve all causes, then select command status in this order:
- cancellation (
130for programmatic, deadline, or SIGINT;143for SIGTERM); - authoritative nonzero child exit or signal projection, preserved exactly
unless coherent offline
--allow-failurespermits exit 1; - start, wait, raw capture, protocol, result-integrity, or incomplete-evidence
failure (
2); - unallowed failing event evidence (
1), except that failure evidence conflicting with a zero child exit is an integrity failure (2); - an exact unmet minimum-coverage policy after a coherent successful child
(
3); - report rendering or artifact-publication failure (
2); - success (
0).
Use platform-appropriate signal or exit projection when possible. If several
failures share a run, keep the authoritative child status and attach later
failures to diagnostics and summary metadata. A parsed fail with a zero child
exit is an integrity conflict, not permission to report success.
The report command has no new child status. Copy explicitly selected external
event, stderr, and coverage evidence into their canonical managed names before
analysis. Import bound same-named stderr/profile siblings from an explicitly
selected external status bundle when no explicit companion overrides them.
Remove stale managed companions that are not selected or bound, while leaving
unknown files untouched.
Trust imported status only when the selected strict run.json
cryptographically binds the selected evidence. Re-encode an external valid
status document canonically at the managed run.json path, but do not rewrite
a status file already at that exact managed path during an ordinary rerender.
For a policy-free report --no-coverage, remove the profile and its binding,
canonically rewrite managed status only when that projection changes it, and
preserve all child/cancellation/issue fields and retained evidence bindings.
If status records a coverage policy, reject report --no-coverage before
artifact preparation so the command cannot erase an authoritative decision or
mutate the bundle. Render a bare log as incomplete for inspection, return
infrastructure failure, and withhold the manifest. Never consume an unrelated
default run.json for an explicit custom event stream.
Acceptance scenarios
- A passing run streams raw JSONL, produces measured results, and returns zero.
- A normal
go testfailure still generates reports and returns the child's nonzero status. - A compile failure represented by text or
BuildEventappears in normalized build failures even without a completed test. - Two occurrences of the same package and test name have different ordinals and independent outcome/duration/output.
- A malformed or oversized record remains in raw evidence, yields a bounded diagnostic, and leaves affected active state incomplete.
- Output beyond the per-occurrence report bound is marked as truncated while the raw JSONL remains byte-for-byte complete.
- A helper publishes a complete PID record atomically; partial observations cannot trigger parsing, leaked goroutines, or reused-PID signaling.
- Cancellation terminates descendants, drains both streams, reaps the child, and returns cancellation even if rendering later fails.
- A renderer failure after a child test failure is reported but does not replace the child failure status.