flamethrower 0.1.1

Deterministic cognition ledger using power_house (and optional pent_house).
Documentation
//! Flamethrower core: deterministic shard minting, verification, and ledger.
//! Only `power_house` (and optionally `pent_house` under `commercial` feature).

use std::fmt;
use std::fs::{File, OpenOptions};
use std::io::{Read, Write};
use std::path::Path;
use std::time::SystemTime;

#[cfg(feature = "commercial")]
use pent_house::{ResonanceEngine, ResonanceLedger};
use power_house::{Field, SumClaim};

/// Canonical shard derived from (label, seed)
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Shard {
    pub label: String,
    pub seed: u64,
    /// Transcript checksum derived from Field arithmetic as a stand-in digest
    pub checksum: u128,
    /// Energy/score from verification pass
    pub energy: u64,
}

impl Shard {
    pub fn mint(label: &str, seed: u64) -> Result<Self, String> {
        validate_label(label)?;
        // Use a small prime field to compute a reproducible checksum
        let field = Field::new(101);
        // Drive the power_house demo using seed as size hint (bounded)
        let n = ((seed % 16) as usize).max(8);
        let claim = SumClaim::prove_demo(&field, n);
        if !claim.verify_demo() {
            return Err("internal: demo verification failed".into());
        }
        // Fold transcript-like values into a checksum using Field ops
        let mut acc: u128 = 0;
        for (i, b) in format!("{:X?}", claim).bytes().enumerate() {
            let v = ((b as u128) * ((i as u128) + 1)) % 10_000_019;
            acc = acc.wrapping_add(v);
        }
        Ok(Shard {
            label: label.to_string(),
            seed,
            checksum: acc,
            energy: (n as u64) * 11,
        })
    }
}

fn validate_label(s: &str) -> Result<(), String> {
    if s.is_empty() || s.len() > 128 {
        return Err("label length invalid".into());
    }
    if !s
        .chars()
        .all(|c| c.is_ascii_alphanumeric() || c == '-' || c == '_')
    {
        return Err("label contains invalid characters".into());
    }
    Ok(())
}

/// Append-only ledger with cumulative digest based on field-like arithmetic only.
#[derive(Default)]
pub struct Ledger {
    shards: Vec<Shard>,
    state: u128, // cumulative digest
}

impl Ledger {
    pub fn new() -> Self {
        Self {
            shards: vec![],
            state: 1,
        }
    }

    pub fn ingest(&mut self, shard: Shard) -> Result<Report, String> {
        // Re-verify by re-minting
        let expect = Shard::mint(&shard.label, shard.seed)?;
        if !constant_time_eq_u128(shard.checksum, expect.checksum) {
            return Err("verification failed: checksum mismatch".into());
        }
        // Update digest via simple multiplicative fold
        self.state = self.state.wrapping_mul(shard.checksum.wrapping_add(17));
        self.shards.push(shard.clone());
        Ok(Report {
            energy: shard.energy,
            confidence: 1.0,
        })
    }

    pub fn digest(&self) -> u128 {
        self.state
    }

    pub fn len(&self) -> usize {
        self.shards.len()
    }

    pub fn is_empty(&self) -> bool {
        self.shards.is_empty()
    }
    pub fn persist_to<P: AsRef<Path>>(&self, path: P) -> Result<(), String> {
        let mut f = OpenOptions::new()
            .create(true)
            .write(true)
            .truncate(true)
            .open(path)
            .map_err(|e| e.to_string())?;
        for sh in &self.shards {
            writeln!(f, "{} {} {} {}", sh.label, sh.seed, sh.checksum, sh.energy)
                .map_err(|e| e.to_string())?;
        }
        f.sync_all().map_err(|e| e.to_string())?;
        Ok(())
    }

    pub fn load_from<P: AsRef<Path>>(path: P) -> Result<Self, String> {
        let mut s = String::new();
        File::open(path.as_ref())
            .map_err(|e| e.to_string())?
            .read_to_string(&mut s)
            .map_err(|e| e.to_string())?;
        let mut me = Ledger::new();
        for line in s.lines() {
            let parts: Vec<&str> = line.split_whitespace().collect();
            if parts.len() != 4 {
                continue;
            }
            let label = parts[0].to_string();
            let seed: u64 = parts[1].parse().map_err(|_| "bad seed")?;
            let checksum: u128 = parts[2].parse().map_err(|_| "bad checksum")?;
            let energy: u64 = parts[3].parse().map_err(|_| "bad energy")?;
            let sh = Shard {
                label,
                seed,
                checksum,
                energy,
            };
            me.state = me.state.wrapping_mul(sh.checksum.wrapping_add(17));
            me.shards.push(sh);
        }
        Ok(me)
    }
}

#[inline]
fn constant_time_eq_u128(a: u128, b: u128) -> bool {
    let mut x = a ^ b;
    x |= x >> 64;
    x |= x >> 32;
    x |= x >> 16;
    x |= x >> 8;
    x |= x >> 4;
    x |= x >> 2;
    x |= x >> 1;
    (x & 1) == 0
}

pub struct Report {
    pub energy: u64,
    pub confidence: f64,
}

impl fmt::Display for Report {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "{{\"energy\":{},\"confidence\":{}}}",
            self.energy, self.confidence
        )
    }
}

/// Simple structured log to stdout as JSON using only std
pub fn log_json(event: &str, msg: &str) {
    let ts = SystemTime::now()
        .duration_since(SystemTime::UNIX_EPOCH)
        .unwrap()
        .as_millis();
    println!(
        "{{\"ts\":{},\"event\":\"{}\",\"msg\":\"{}\"}}",
        ts,
        esc(event),
        esc(msg)
    );
}

fn esc(s: &str) -> String {
    s.replace('\"', "\\\"")
}

#[cfg(feature = "commercial")]
pub fn commercial_banner() -> Result<(), String> {
    if std::env::var("FLAME_ALLOW_COMMERCIAL").ok().as_deref() != Some("1") {
        return Err("Commercial mode requires FLAME_ALLOW_COMMERCIAL=1 and a valid license".into());
    }
    Ok(())
}