Add --ledger-file arg for explicit ledger path control

Defaults to <output_dir>/run_ledger.jsonl as before.
Pass --ledger-file to read from (and write to) a specific ledger,
enabling multiple ledger files to seed different search campaigns
or merge results from separate runs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-10 13:10:22 +02:00
parent a0316be798
commit 0945c94cc8
2 changed files with 17 additions and 7 deletions

View File

@@ -205,8 +205,12 @@ pub async fn run(cli: &Cli) -> Result<()> {
let system = prompts::system_prompt(schema, claude.family());
info!("model family: {}", claude.family().name());
// Resolve ledger path: explicit --ledger-file takes precedence, else <output_dir>/run_ledger.jsonl
let ledger_path = cli.ledger_file.clone().unwrap_or_else(|| cli.output_dir.join("run_ledger.jsonl"));
info!("ledger: {}", ledger_path.display());
// Load prior runs from ledger and build cross-run context for iteration 1
let prior_summary = load_prior_summary(&cli.output_dir, &swym).await;
let prior_summary = load_prior_summary(&ledger_path, &swym).await;
// Agent state
let mut history: Vec<IterationRecord> = Vec::new();
@@ -412,7 +416,7 @@ pub async fn run(cli: &Cli) -> Result<()> {
info!(" condition audit: {}", serde_json::to_string_pretty(audit).unwrap_or_default());
}
}
append_ledger_entry(&cli.output_dir, &result, &strategy);
append_ledger_entry(&ledger_path, &result, &strategy);
results.push(result);
}
Err(e) => {
@@ -599,7 +603,7 @@ async fn run_single_backtest(
}
/// Append a ledger entry for a completed backtest so future runs can learn from it.
fn append_ledger_entry(output_dir: &Path, result: &BacktestResult, strategy: &Value) {
fn append_ledger_entry(ledger: &Path, result: &BacktestResult, strategy: &Value) {
// Skip nil run_ids (error placeholders)
if result.run_id == Uuid::nil() {
return;
@@ -620,11 +624,10 @@ fn append_ledger_entry(output_dir: &Path, result: &BacktestResult, strategy: &Va
return;
}
};
let path = output_dir.join("run_ledger.jsonl");
if let Err(e) = std::fs::OpenOptions::new()
.append(true)
.create(true)
.open(&path)
.open(ledger)
.and_then(|mut f| writeln!(f, "{}", line))
{
warn!("could not write ledger entry: {e}");
@@ -634,8 +637,8 @@ fn append_ledger_entry(output_dir: &Path, result: &BacktestResult, strategy: &Va
/// Load the run ledger, fetch metrics via the compare endpoint, and return a compact
/// prior-results summary string for the initial prompt. Returns `None` if the ledger
/// is absent, empty, or the compare call fails.
async fn load_prior_summary(output_dir: &Path, swym: &SwymClient) -> Option<String> {
let path = output_dir.join("run_ledger.jsonl");
async fn load_prior_summary(ledger: &Path, swym: &SwymClient) -> Option<String> {
let path = ledger;
let contents = std::fs::read_to_string(&path).ok()?;
// Parse all ledger entries

View File

@@ -118,6 +118,13 @@ pub struct Cli {
#[arg(long, default_value = "./results")]
pub output_dir: PathBuf,
/// Path to the run ledger JSONL file used for cross-run learning.
/// Defaults to <output_dir>/run_ledger.jsonl when not specified.
/// Pass a different path to seed a new run from a specific ledger
/// (e.g. a curated export from a previous campaign).
#[arg(long)]
pub ledger_file: Option<PathBuf>,
/// Poll interval in seconds when waiting for backtest completion.
#[arg(long, default_value_t = 2)]
pub poll_interval_secs: u64,