changes claude never committed

This commit is contained in:
2026-06-21 18:00:52 -07:00
parent 39386a81c9
commit 2fe989bcb3
33 changed files with 5528 additions and 0 deletions
+13
View File
@@ -0,0 +1,13 @@
[package]
name = "generators"
version.workspace = true
edition.workspace = true
license.workspace = true
[dependencies]
world_model = { path = "../world_model" }
rune_ir = { path = "../rune_ir" }
trace_model = { path = "../trace_model" }
[lib]
path = "src/lib.rs"
+344
View File
@@ -0,0 +1,344 @@
//! `generators` — produce worlds, rune programs, executor sets, semantic
//! contracts, and perturbation batches. Generators must reject flat cases:
//! every generated case is checked against the generated-case gates before it
//! is admitted to the corpus.
use rune_ir::{Op, RuneProgram, RuneToken, ALL_OPS};
use trace_model::numeric_rank;
use world_model::{
standard_executors, ContractId, ExecutionContext, PerturbationAxis, ProgramId, Rng,
TraceDifferenceExpectation, WorldId, WorldSnapshot, HIDDEN_LANES, LANES, NUM_DOMAINS,
};
/// Minimum domain reference entropy (bits) a generated program must show.
pub const MIN_DOMAIN_ENTROPY: f64 = 2.5;
/// Semantic contract (per spec) with the default thresholds.
#[derive(Clone, Copy, PartialEq, Debug)]
pub struct SemanticContract {
pub id: ContractId,
pub min_causal_rank: usize,
pub min_domain_participation: usize,
pub min_future_sensitivity: f64,
pub min_context_divergence: f64,
pub max_compressibility: f64,
}
impl SemanticContract {
pub fn default_with_seed(seed: u64) -> Self {
SemanticContract {
id: ContractId(seed),
min_causal_rank: 6,
min_domain_participation: 4,
min_future_sensitivity: 0.50,
min_context_divergence: 0.40,
max_compressibility: 0.70,
}
}
}
/// One perturbed variant of a base world.
pub struct PerturbedCase {
pub axis_name: String,
pub world: WorldSnapshot,
pub expectation: TraceDifferenceExpectation,
}
/// A complete generated case (per spec).
pub struct GeneratedCase {
pub world: WorldSnapshot,
pub program: RuneProgram,
pub contexts: Vec<ExecutionContext>,
pub contract: SemanticContract,
pub perturbations: Vec<PerturbedCase>,
pub world_seed: u64,
pub program_seed: u64,
pub contract_seed: u64,
pub perturbation_seed: u64,
}
/// Generate a rich world from a seed.
pub fn generate_world(seed: u64) -> WorldSnapshot {
let mut rng = Rng::derive(seed, "world");
let mut w = WorldSnapshot::blank(WorldId(seed), seed);
for (i, d) in w.domains.iter_mut().enumerate() {
let spread = 1000 + (i as i64) * 137;
for l in 0..LANES {
d.observed[l] = rng.range_i64(-spread, spread);
}
for l in 0..HIDDEN_LANES {
let mut v = rng.range_i64(-spread, spread);
if v == 0 {
v = 1 + i as i64;
}
d.hidden[l] = v;
}
}
for j in 0..NUM_DOMAINS {
for i in 0..NUM_DOMAINS {
w.causal_state.coupling[j][i] = rng.range_i64(-17, 17);
}
}
for di in 0..NUM_DOMAINS {
for l in 0..LANES {
w.observation_state.visible[di][l] = !rng.chance(0.15);
}
if (0..LANES).all(|l| !w.observation_state.visible[di][l]) {
w.observation_state.visible[di][0] = true;
}
}
w.observation_state.noise_seed = rng.next_u64();
for r in w.execution_state.accumulator.iter_mut() {
*r = rng.range_i64(-50, 50);
}
w
}
/// Generate a rune program from a seed. Construction guarantees every opcode
/// appears and every domain is both read and written, so the case is never
/// flat.
pub fn generate_program(seed: u64) -> RuneProgram {
let mut rng = Rng::derive(seed, "program");
let len = 28 + rng.below(13); // 28..=40
let mut tokens = Vec::with_capacity(len);
for i in 0..len {
let op = if rng.chance(0.7) {
ALL_OPS[i % ALL_OPS.len()]
} else {
Op::from_u8(rng.next_u64() as u8)
};
// 3 and 5 are coprime with 8, so src/dst sweep all domains.
let a = ((i * 3 + rng.below(2)) % NUM_DOMAINS) as u8;
let mut b = ((i * 5 + 1 + rng.below(2)) % NUM_DOMAINS) as u8;
if b == a {
b = (b + 1) % NUM_DOMAINS as u8;
}
tokens.push(RuneToken {
op,
a,
b,
c: rng.next_u64() as u8,
imm: rng.range_i64(-100_000, 100_000),
});
}
RuneProgram {
id: ProgramId(seed),
tokens,
seed,
}
}
/// Generate >= 3 executors.
pub fn generate_contexts(seed: u64) -> Vec<ExecutionContext> {
let mut rng = Rng::derive(seed, "context-count");
standard_executors(seed, 3 + rng.below(2))
}
/// Build the perturbation batch for a world (>= 10 perturbations drawn from
/// domain surfaces).
pub fn generate_perturbations(world: &WorldSnapshot, seed: u64, count: usize) -> Vec<PerturbedCase> {
use world_model::WorldDomain;
let count = count.max(10);
let mut axes: Vec<Box<dyn PerturbationAxis>> = Vec::new();
for d in &world.domains {
axes.extend(d.perturbation_axes());
}
let mut rng = Rng::derive(seed, "perturb");
let mut out = Vec::with_capacity(count);
for k in 0..count {
let idx = (k * 7 + rng.below(axes.len())) % axes.len();
let axis = &axes[idx];
out.push(PerturbedCase {
axis_name: axis.name(),
world: axis.apply(world),
expectation: axis.expected_trace_difference(),
});
}
out
}
/// Generate a full case from a master seed.
pub fn generate_case(master_seed: u64) -> GeneratedCase {
let world_seed = derive(master_seed, "world");
let program_seed = derive(master_seed, "program");
let contract_seed = derive(master_seed, "contract");
let perturbation_seed = derive(master_seed, "perturb");
let world = generate_world(world_seed);
let program = generate_program(program_seed);
let contexts = generate_contexts(master_seed);
let contract = SemanticContract::default_with_seed(contract_seed);
let perturbations = generate_perturbations(&world, perturbation_seed, 10);
GeneratedCase {
world,
program,
contexts,
contract,
perturbations,
world_seed,
program_seed,
contract_seed,
perturbation_seed,
}
}
pub fn derive(seed: u64, tag: &str) -> u64 {
let mut h = world_model::Hasher::new();
h.write_tag(tag);
h.write_u64(seed);
h.finish().0
}
// ---------------------------------------------------------------------------
// Generated-case gates: reject flat cases.
// ---------------------------------------------------------------------------
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct CaseEstimate {
pub estimated_causal_rank: usize,
pub domain_entropy: f64,
pub perturbation_axes: usize,
pub executor_count: usize,
pub future_dependence: bool,
pub hidden_observed_divergence: bool,
pub nonuniform_fingerprints: bool,
}
impl GeneratedCase {
/// Estimate the structural richness of the case without running a runtime.
pub fn estimate(&self) -> CaseEstimate {
let mut adj = [[0.0f64; NUM_DOMAINS]; NUM_DOMAINS];
let mut refs = [0u32; NUM_DOMAINS];
for t in &self.program.tokens {
let s = t.src_domain();
let d = t.dst_domain();
let phase = 1.0 + t.lane() as f64 + 4.0 * t.lane2() as f64;
adj[d][s] += phase;
adj[d][d] += 0.5 + t.mode() as f64;
refs[s] += 1;
refs[d] += 1;
}
let rows: Vec<Vec<f64>> = adj.iter().map(|r| r.to_vec()).collect();
let est_rank = numeric_rank(&rows);
let total: u32 = refs.iter().sum();
let mut entropy = 0.0;
if total > 0 {
for &c in &refs {
if c > 0 {
let p = c as f64 / total as f64;
entropy -= p * p.log2();
}
}
}
let future = self.program.tokens.iter().any(|t| matches!(t.op, Op::Schedule));
let hidden_div = self
.world
.domains
.iter()
.any(|d| d.hidden.iter().any(|&v| v != 0))
|| self
.world
.observation_state
.visible
.iter()
.any(|row| row.iter().any(|&v| !v));
use world_model::WorldDomain;
let mut prints: Vec<_> = self.world.domains.iter().map(|d| d.fingerprint().hash).collect();
prints.sort();
prints.dedup();
let nonuniform = prints.len() > 1;
CaseEstimate {
estimated_causal_rank: est_rank,
domain_entropy: entropy,
perturbation_axes: self.perturbations.len().max(count_axes(&self.world)),
executor_count: self.contexts.len(),
future_dependence: future,
hidden_observed_divergence: hidden_div,
nonuniform_fingerprints: nonuniform,
}
}
}
fn count_axes(world: &WorldSnapshot) -> usize {
use world_model::WorldDomain;
world.domains.iter().map(|d| d.perturbation_axes().len()).sum()
}
/// Reasons a case failed the generated gates (empty = passed).
pub fn generated_gate_failures(est: &CaseEstimate) -> Vec<String> {
let mut f = Vec::new();
if est.estimated_causal_rank < 6 {
f.push(format!("estimated_causal_rank {} < 6", est.estimated_causal_rank));
}
if est.domain_entropy < MIN_DOMAIN_ENTROPY {
f.push(format!(
"domain_entropy {:.3} < {:.3}",
est.domain_entropy, MIN_DOMAIN_ENTROPY
));
}
if est.perturbation_axes < 10 {
f.push(format!("perturbation_axes {} < 10", est.perturbation_axes));
}
if est.executor_count < 3 {
f.push(format!("executor_count {} < 3", est.executor_count));
}
if !est.future_dependence {
f.push("future_dependence absent".into());
}
if !est.hidden_observed_divergence {
f.push("no hidden/observed divergence".into());
}
if !est.nonuniform_fingerprints {
f.push("uniform domain fingerprints".into());
}
f
}
/// Generate a case that passes the generated gates, retrying with fresh seeds.
pub fn generate_accepted_case(master_seed: u64) -> (GeneratedCase, u64) {
let mut s = master_seed;
for _ in 0..64 {
let case = generate_case(s);
if generated_gate_failures(&case.estimate()).is_empty() {
return (case, s);
}
s = derive(s, "retry");
}
let case = generate_case(s);
(case, s)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn accepted_cases_pass_generated_gates() {
for i in 0..200u64 {
let (case, _) = generate_accepted_case(0x1234 ^ i.wrapping_mul(0x9e3779b97f4a7c15));
let failures = generated_gate_failures(&case.estimate());
assert!(failures.is_empty(), "case {i} failed: {:?}", failures);
assert!(case.contexts.len() >= 3);
assert!(case.perturbations.len() >= 10);
}
}
#[test]
fn generation_is_deterministic() {
let (a, sa) = generate_accepted_case(999);
let (b, sb) = generate_accepted_case(999);
assert_eq!(sa, sb);
assert_eq!(a.program.content_hash(), b.program.content_hash());
assert_eq!(a.world.content_hash(), b.world.content_hash());
}
}