Cross-run consolidation¶
ConsolidationStore archives what a run produced; seed_from_archive
retrieves it for the next run — gated. This is the difference between
self-improvement (one run) and continuing self-improvement (skills that seed
the next run).
CLI / plugin path.
agentdescent evolve,start, and the host plugins never write a consolidation archive. Only the Python meta API (continuous_meta_runand friends; see also meta-cli for the read-only verbs that inspect one) produces$AGENTDESCENT_HOME/archive. A missing archive is not fixed by inventing a "consolidation" CLI step.
Why¶
An evolution run starts from an empty artifact, learns, and then the skill dies with the process that made it. The trajectory ledger records what happened during a run; the archive records what it produced — the artifact that survived, its measured reward, the configuration that made it, and the trajectories that justify it — so a later run can adopt it.
The pieces¶
| Piece | What it is |
|---|---|
ConsolidationStore(path) |
A durable archive: one JSON record per run under <path>/runs/<sha256(run_id)>.json (the complete id is hashed, so a/b and ab never collide; the full run_id is stored in the record, and a pre-#338 sanitized <run_id>.json is still found by find when its stored id matches). Atomic, idempotent by run_id, thread-safe. |
ConsolidationStore.archive(result, *, run_id, artifact_id, strategy, config, trajectory_store) |
Writes a run's product (the artifact's state, rendered, final_reward, rounds) plus the caller's config (dataset/scorer/model/params) and a durable trajectory_store path — linked, not copied. |
seed_from_archive(store, tasks, run, reward, *, strategy, config, sample, min_reward, seed) |
Retrieves a candidate and returns (initial_state, SeedReport). Pass initial_state to evolve(initial_state=...). |
The guards¶
- Mini-eval gate. The archived artifact and the empty seed are both scored
on a seeded sample of the new tasks; the archived state is handed over only
if it does not regress beyond
min_rewardagainst the empty baseline. A harmful cross-domain seed is refused and reported, never installed. - Same configuration first. Archived runs whose
configfingerprint matches the new run's rank first, then by measured reward.configis how the caller keeps domains apart; a run without a config matches nothing. - Same strategy. A new run adopts the state only through a strategy of the
same name (its
to_diff/rendermust understand the keys). - Non-finite rewards refused. A run with a
NaN/out-of-rangefinal_rewardis not archived.
Example¶
Run 1 evolves a capability-capped skill and archives it; run 2 (new tasks) retrieves it through the gate and reaches the quality bar ~200× sooner than the empty seed — measured, deterministic, offline.