Why
#80: CI history is instance-local and should not travel with a clone or backup. At the time of the move, runs/ was 849 of the 959 files on the vole branch, and every human metadata write carried them.
What changed
data/runs.dbnow stores every finished attempt:run_attempts,run_steps,run_attempt_artifacts, plus the existing log, attestation, and artifact rows.RecordAttemptwrites the attempt and the run’s result in one transaction.- The runner sends the record with
finishover the lease’s SSH channel. The server checks the account, run, attempt, commit, workflow, job, steps digest, and image, and verifies every log and artifact pointer is in the object store. - The runner no longer pushes a record commit. A tagged build pushes its release pointers after the record is stored, so a release cannot exist without the build record.
- Pre-receive rejects additions and edits under
runs/; deletions are allowed for cleanup. vole admin index rebuildimports records still on an oldvolebranch (ImportLegacyRecords), idempotently and without deleting database records. It is the upgrade path.- The run page reads the stored attempt; the “commit that records it” link is gone.
data/runs.dbis documented as a source of truth: backup and restore include it, and the upgrade notes say server and runners move together.
What this deliberately does not do
Existing runs/ files remain in past commits, and in the current tip until an operator deletes them. Removing them from history would require rewriting the protected vole branch and every clone, which the workflow forbids. New records never go there.
Tests
ci/runs:RecordAttemptstores once, is idempotent on retry, refuses different bytes for the same attempt, and refuses a record for another commit.server/ssh: finish with no record, wrong account, wrong attempt, wrong commit, the real record, an idempotent retry, and a changed record.server/hook: a push addingruns/is refused and names the database.serverintegration: an end-to-end run stores the attempt in the database and leaves no record on the branch;index rebuildimports a legacy record; a release build pushes pointers and noruns/.- Existing record tests still cover the legacy import format.
Checks
go test -count=1 ./...go test -race ./ci/runs ./ci/agent ./server/ssh ./server/hook ./server/webgo vet ./...vole workflow checkvole workflow run verify
Rollout
Server and runners must be upgraded together; an older runner’s finish carries no record and is refused. Run vole admin index rebuild once to import old records, then back up runs.db.