0023. Archiving keeps a run's summary and drops its data
- Status: Accepted, 2026-10-12
Context
Section titled “Context”Retention (decision 0020) deletes runs. Deleting loses the one thing worth keeping for a long time: what the run measured. A run’s metric summaries, gates, usage and spec are small and live in the run record. Its records, outputs and results are large, and are what a run costs to keep.
Decision
Section titled “Decision”ArchiveRundrops a finished run’srun_records,run_outputs,run_resultsand webhook deliveries, in one transaction, and setsRun.archived_at. The run, its labels and project stay. It hasDeleteRun’s conditions (finished, not leased) and idempotency (archiving twice returns the run unchanged).- It takes the
runs.deletepermission. It removes what deleting removes, so no new permission or role change is needed. Archiving is audited asruns.delete, like a refused or allowedDeleteRun. - Every reader says why it cannot proceed.
ListRunResults,ResumeRun,CompareRuns,PromoteResultsand a dataset taken from a run answerFailedPrecondition(orInvalidArgumentfor a dataset) naming the archive.SliceRunsskips archived runs.GetRun,ListRunsandDeleteRunwork as before. - Automatic archiving is
runs.archive_afterandruns.project_archive_after(“0” never), run by the retention janitor each hour, before deletion is considered. It must be shorter than the retention it is combined with, checked at startup.evalsi.keep: "true"exempts a run from both. - Automatic actions are audited. Each automatic delete or archive writes an event with principal
system:retention, actionruns.deleteorruns.archive,procedure: runs.Retainand the cutoff indetail.
Consequences
Section titled “Consequences”- An archived run still counts toward
max_stored_runs: the quota counts rows, and counting only whole runs would need a column and a migration for databases that already exist. Delete archived runs to free it, or set retention. - The janitor reads every run older than
archive_afterthat has not been deleted, each hour, to find the ones not yet archived. With no retention the set only grows; the read is of run summaries, not results. - Anything that reads results or compares an archived run fails with a clear message:
evalsi analyzeskips archived runs when listing and refuses one named with--run,evalsi report --servershows the summary only, andevalsi compare, the flywheel commands and a checkpoint regression gate against an archived base-model run answerFailedPrecondition. Label runs you compare againstevalsi.keep: "true", or setarchive_afterlonger than they are needed. - Not built: per-label retention rules (only the
evalsi.keepexemption), and an “unarchive”. Data already delivered to sinks and promoted datasets are untouched.