Evidence
Gin remembers what executors and CI observed about exact source trees. It runs nothing itself: Toki, CI or an agent harness runs the commands and reports results, and Gin stores them, checks them and answers questions about them.
Evidence is optional. Source operations do no evidence work, and an empty evidence store costs nothing beyond its tables.
Observations
An observation records:
- the exact tree it ran against (the subject);
- the evaluation family: test, build or CI check;
- the harness identity, including test selection and shard;
- the action definition and command, versioned configuration, dependency pins and input fingerprints;
- an environment fingerprint: OS, architecture, runner image, toolchain pins and allow-listed environment variables (a missing component is unknown, never assumed);
- reported status, start and end times, logs and artifacts with content identities, and the typed executor or CI payload.
Execution provenance (who ran it, which checkpoint, which Git commit) is kept beside the subject. A rewrite never changes an observation's subject or moves it.
Trust levels
| Trust | Meaning |
|---|---|
| agent claim | an untrusted statement; may report a pass as context, never counts as one |
| executor reported | verified against source Gin served, or a verified CI upload |
| trusted runner | executor reported plus an attestation the deployment's runner policy accepts |
| derived | computed from other observations (for example a flaky mark); status is always unknown |
A signature, principal or TLS session never raises trust on its own. Verification that fails refuses the upload rather than silently downgrading or rewriting it.
Append-only logs
Evidence lives in per-repository logs, each with its own sequence starting at 1; there is no global order. Ingestion is idempotent: an exact retry returns the original acknowledgement, while different bytes under the same retry key are a conflict.
Corrections and retractions are new records naming an existing observation of the same tree. The original stays readable. Queries return observations and their revisions, never a synthesised "current pass". All evidence queries need repository read access.
Execution receipts
A receipt reports one execution: the exact selected tests, scope, filter, shard, attempts, and every test's outcome (passed, failed, skipped, timed out, cancelled or indeterminate), bound to the subject tree and the environment fingerprint.
- A missing or indeterminate outcome is never a pass.
- Only an unfiltered, unsharded selection of exactly one scope, with every test reported, completes that scope; only one where every test passed proves it passed.
Receipts are sent with the gin.v1 operations IngestReceipt and recovered with ReceiptAcceptance.
Current limit
gin serve does not yet verify that a receipt's tree is one it served to the executor, so executor-reported receipts are refused for now. Agent-claim receipts are accepted as untrusted observations. Until that verifier lands, only CI-bound identities have evidence write rights in the daemon.
CI uploads
gin ci upload runs as a CI job step after the tests, with the job's machine-identity token:
sh
gin ci upload --endpoint https://gin.example:7400 \
--repository gin:blake3:v1:repository:<hex> \
--junit target/nextest/ci/junit.xml --metadata target/nextest/ci/junit-metadata.json \
--artifact junit-core-1 --token-env GIN_TOKEN --step successIt reads the run from GitHub Actions variables (GITHUB_REPOSITORY, GITHUB_RUN_ID, GITHUB_RUN_ATTEMPT, GITHUB_EVENT_NAME, GITHUB_SHA and, for pull requests, GITHUB_EVENT_PATH), and the tested commit's object, tree and parents from the checkout (--checkout DIR, default the current directory). It uploads the per-test results and, with --step, that step's conclusion.
A step report is never the check run's conclusion: the job has not ended when the client runs. Gin refuses check-run conclusions from uploads.
Configuring a CI identity
Bind the CI identity to the GitHub repository and workflows it reports for:
text
identity ci-myproject token-env GIN_TOKEN_CI
grant ci-myproject repository gin:blake3:v1:repository:<hex> operations upload_ci_run,receipt_acceptance
ci ci-myproject repository gin:blake3:v1:repository:<hex> github acme/myproject workflows .github/workflows/ci.ymlWhen an upload counts as verified
The daemon records an upload as executor reported only when:
- the identity's
ciline covers its Gin repository, GitHub repository and workflow; - the commit object hashes to the tested commit and names the recorded tree and parents;
- the tested commit is the one the run was triggered for;
- a pull-request run tested the merge commit of exactly its base and head.
Anything else is recorded as an agent claim: an explicitly untrusted observation. Any difference in run configuration makes a different subject.
Baseline classification
When a test fails deep in a stack of dependent work, Gin can say what comparable evidence it already holds, without a checkout. It walks the failing state's ancestors nearest first, at any depth, and stops at the first tree with comparable evidence of that test.
Comparable means a trusted producer, the same repository, kind, test identity, action and configuration, an unprivileged job recording its OS image, and an exactly matching, fully known environment fingerprint. Any toolchain or variable difference makes a run incomparable.
The answer is one of: pre-existing, new, unknown, incomparable or suspected flaky. It compares normalised failure signatures, not only test names, and states that an earlier failure does not prove the same root cause. Gin recommends; the orchestrator or CI policy decides whether to rerun.
Reuse is advisory
A result could stand for a run that has not happened only if its strict reuse key matches exactly: the whole effective tree, action, configuration, environment fingerprint and the rest, every component known, and the test cleared as hermetic. There is no partial match or similarity score.
Today reuse is advisory only. gin plan (and ValidatePlan) reports each check as reusable, uncertain or required, with the evidence it rests on:
sh
gin --host DIR --repository ID --workspace ID --data DATA --principal NAME \
plan --snapshot CHECKPOINT --evaluation HEXHEX is a gin.v1.EvaluationKey (the check with its strict reuse key) in hexadecimal protobuf encoding; a check named alone is never reusable. --data names a stopped gin serve data directory, which holds the evidence store. Reusable checks are labelled would-reuse and counted as avoidable, but nothing is skipped (may_skip stays false). Requests can demand fresh evidence or a trusted runner.
Hermetic clearance is decided per test at query time, from the operator's approved list, the reusable-runner rules (unprivileged job, cleared environment, fixed HOME and TMPDIR, recorded OS image) and a perturbation rerun showing the outcome does not change.
Following validated publications
A dependent workspace can follow a channel in latest-validated mode: it is offered the newest publication whose exact tree has a standing pass of one named evaluation at executor-reported or trusted-runner level. Agent claims never validate. A later failure or retraction moves the offer back.
Not yet exposed
Follow modes have no API or CLI operation yet; they are set through the Rust workspace API.