echo-1 / src /main.rs
lupodevelop's picture
echo-1 Stage 0 explainer: diffusion vs autoregressive, execution-verified
3afc977 verified
Raw
History Blame Contribute Delete
3.64 kB
//! echo-1 M0 data engine.
//!
//! Generates pure-Lua functions, executes them in a deterministic sandbox,
//! filters to the clean-terminating observable ones, and writes a JSONL dataset
//! where each record carries an I/O spec (synthesis), a prefix/hole/suffix spec
//! (infilling), and held-out tests for execution-based verification.
mod grammar;
mod mutate;
mod pipeline;
mod sandbox;
mod spec;
mod value;
mod verify;
use std::io::{BufRead, Write};
use anyhow::Result;
use clap::{Parser, Subcommand};
use serde::{Deserialize, Serialize};
use spec::IoPair;
#[derive(Parser)]
#[command(name = "echo-data", about = "echo-1 M0 data engine")]
struct Cli {
#[command(subcommand)]
cmd: Cmd,
}
#[derive(Subcommand)]
enum Cmd {
/// Generate a dataset of verified pure-Lua programs.
Gen {
/// Number of programs to keep.
#[arg(short, long, default_value_t = 100)]
count: usize,
/// Master RNG seed (reproducible).
#[arg(short, long, default_value_t = 1)]
seed: u64,
/// Fix difficulty 0..=4; omit to round-robin.
#[arg(short, long)]
difficulty: Option<u8>,
/// Shown I/O examples per program.
#[arg(long, default_value_t = 3)]
examples: usize,
/// Held-out tests per program.
#[arg(long, default_value_t = 5)]
tests: usize,
/// Instruction budget per execution (deterministic timeout).
#[arg(long, default_value_t = 200_000)]
budget: i64,
/// Output JSONL path.
#[arg(short, long, default_value = "data/dataset.jsonl")]
out: String,
/// Skip the mutation gate (much faster; for bulk training data).
#[arg(long, default_value_t = false)]
no_gate: bool,
},
/// Verify candidate programs from stdin against their tests (one JSON object
/// per line: {"source":..., "tests":[{"input":[...],"output":...}]}). Emits
/// one result object per line. Same sandbox/verifier used to label data.
VerifyBatch {
/// Instruction budget per execution.
#[arg(long, default_value_t = 200_000)]
budget: i64,
},
}
#[derive(Deserialize)]
struct Candidate {
source: String,
tests: Vec<IoPair>,
}
#[derive(Serialize)]
struct VerifyOut {
pass: bool,
verdict: String,
}
fn verify_batch(budget: i64) -> Result<()> {
let sb = sandbox::Sandbox::new().map_err(|e| anyhow::anyhow!("init sandbox: {e}"))?;
let stdin = std::io::stdin();
let stdout = std::io::stdout();
let mut out = std::io::BufWriter::new(stdout.lock());
for line in stdin.lock().lines() {
let line = line?;
if line.trim().is_empty() {
continue;
}
let cand: Candidate = serde_json::from_str(&line)?;
let verdict = verify::verify(&sb, &cand.source, &cand.tests, budget);
let res = VerifyOut {
pass: verdict == verify::Verdict::Pass,
verdict: format!("{verdict:?}"),
};
writeln!(out, "{}", serde_json::to_string(&res)?)?;
}
out.flush()?;
Ok(())
}
fn main() -> Result<()> {
let cli = Cli::parse();
match cli.cmd {
Cmd::Gen { count, seed, difficulty, examples, tests, budget, out, no_gate } => {
pipeline::run(pipeline::GenParams {
count,
seed,
fixed_difficulty: difficulty,
n_examples: examples,
n_tests: tests,
budget,
out,
gate: !no_gate,
})
}
Cmd::VerifyBatch { budget } => verify_batch(budget),
}
}