fv-compute 0.2.0

The FusionVault transform/compute contract: a transform is a typed function over Arrow data declared by a manifest, discovered by a registry, and run by a pluggable backend.
Documentation
//! # fv-compute — the transform/compute contract
//!
//! A transform is a typed function over Arrow data with a declared
//! [capability envelope](capability::CapabilityEnvelope), described by a [`TransformManifest`]
//! (`transform.toml`) against **one** contract and executed by a pluggable [`TransformBackend`]
//! chosen by the manifest's IMPL. This crate is the "define once" seam: the manifest schema and
//! its validation (the publish gate), the envelope and binding enforcement, the Arrow-typed
//! signature, the directory-per-transform [`registry`], and the dispatch traits the backends
//! implement (`fv-compute-wasm`, `fv-compute-container`, or your own).
//!
//! It is a library any caller embeds — a pipeline runner, a materializer, an action runtime, a
//! REPL — so a transform is reusable outside any one pipeline. `wit/transform.wit` is the same
//! contract for WASM components; the container protocol mirrors it for processes.
//!
//! ```
//! use fv_compute::{parse_and_validate, ImplKind};
//! let m = parse_and_validate(r#"
//!     id = "marginPct"
//!     version = "1.0.0"
//!     impl = "expression"
//!     entry = "src/expr.fvx"
//!     [[inputs]]
//!     columns = [{ name = "revenue", type = "float64" }, { name = "cost", type = "float64" }]
//!     [output]
//!     columns = [{ name = "marginPct", type = "float64" }]
//! "#).unwrap();
//! assert_eq!(m.impl_kind, ImplKind::Expression);
//! ```

/// Every Rust code block in the README is compiled and run as a doctest.
#[cfg(doctest)]
#[doc = include_str!("../README.md")]
pub struct ReadmeDoctests;

pub mod capability;
pub mod catalog;
pub mod contract;
pub mod manifest;
pub mod registry;
pub mod runtime;
pub mod types;

pub use capability::{Binding, CapabilityEnvelope, EnvelopeViolation, Hardware};
pub use catalog::{catalog_json, descriptors, model_descriptors, models_json, FieldInfo, TransformDescriptor};
pub use contract::{Compute, ComputeError, TransformBackend};
pub use manifest::{
    parse_and_validate, ContainerProtocol, ImplKind, Labels, LabelsRule, ManifestError, TransformManifest,
};
pub use registry::{
    standard_registry, Backends, DirRoot, MemoryRoot, RawUnit, RegisteredTransform, Registry, RegistryBuilder,
    RegistryError, RegistryIndex, Root,
};
pub use runtime::{Runtime, RuntimeBuilder};
pub use types::{ColumnSpec, FvType, SchemaSpec};

/// The version of the *contract itself* (independent of any transform's version). Bumped when the
/// manifest shape / WIT interface changes incompatibly; lets a registry reject manifests authored
/// against a future contract.
pub const CONTRACT_VERSION: &str = "0.1.0";

/// Build the transform-index catalogue from a `root[:root…]` spec (paths relative to the current
/// directory): every registered manifest, as JSON, under the contract version. The published
/// contract carries a snapshot of this document and consumers of the registry assert against it,
/// so a registry change cannot silently diverge from the contract. (The `description` text is part
/// of that snapshot; changing it is a contract change.)
pub fn transform_index_payload(roots_spec: &str) -> serde_json::Value {
    use crate::registry::{DirRoot, Registry};
    let mut b = Registry::builder();
    for (i, r) in roots_spec.split(':').filter(|s| !s.is_empty()).enumerate() {
        let name = std::path::Path::new(r)
            .file_name()
            .map(|s| s.to_string_lossy().to_string())
            .unwrap_or_else(|| format!("root{i}"));
        b = b.root(DirRoot::new(name, std::path::PathBuf::from(r)));
    }
    let registry = b.build().expect("build transform registry");
    let transforms: Vec<serde_json::Value> = registry
        .iter()
        .map(|t| serde_json::to_value(&t.manifest).unwrap())
        .collect();
    serde_json::json!({
        "description": "Transform registry catalogue. SINGLE SOURCE = the fv-compute directory-per-transform registry (transforms/ + each business bundle). Generated by `fv-datafusion --emit-transform-index`; the TS pipeline builder reads this to offer registered transforms (container/wasm/expression/builtin) in its palette. Do not hand-edit.",
        "contractVersion": CONTRACT_VERSION,
        "transforms": transforms,
    })
}