Skip to main content

vyre_driver/
materialize.rs

1//! Backend-neutral target-payload admission shared by every concrete driver.
2//!
3//! Materializing a target payload is two neutral checks bracketing one
4//! backend-specific step: admit the payload against the artifact it claims to
5//! implement, decode the dialect image, then project the artifact's resources
6//! onto the instance. Only the middle step is target-specific.
7//!
8//! Copying the neutral halves per backend is what let them drift. Before this
9//! module the same admission checks were written four times, and they had
10//! stopped agreeing: two backends rejected a module whose entry point was not
11//! `main` and two accepted it, and one spelled several shared failures with
12//! different text than the other three. A payload rejected by one backend was
13//! accepted by another for reasons nobody chose.
14
15use std::collections::{BTreeMap, BTreeSet};
16use std::sync::Arc;
17
18use vyre_foundation::ir::Program;
19use vyre_megakernel::{
20    Artifact, ArtifactValueId, FusionRecord, ResourceLifetime, TargetModuleBundle,
21    TargetModuleImage, TargetPayload, TargetPayloadFormat, TargetProfile,
22};
23
24use crate::{BackendError, DispatchConfig};
25
26/// Build the shared "recompile the payload" rejection.
27#[must_use]
28pub fn invalid_module(reason: &str) -> BackendError {
29    BackendError::InvalidProgram {
30        fix: format!("Fix: {reason}. Recompile the target payload from the neutral artifact."),
31    }
32}
33
34/// Build the shared payload-decode failure for `backend`.
35#[must_use]
36pub fn compile_error(backend: &str, error: impl std::fmt::Display) -> BackendError {
37    BackendError::KernelCompileFailed {
38        backend: backend.to_string(),
39        compiler_message: format!(
40            "{error}. Fix: rebuild the target payload from the neutral artifact."
41        ),
42    }
43}
44
45/// What the acquired materializer accepts, as declared by its device.
46#[derive(Clone, Copy, Debug)]
47pub struct MaterializerTarget<'a> {
48    /// Stable identity of the acquiring backend, used in rejection text.
49    pub backend_id: &'a str,
50    /// Payload format the materializer was acquired for.
51    pub format: &'a TargetPayloadFormat,
52    /// Device profile the materializer was acquired for.
53    pub profile: &'a TargetProfile,
54}
55
56/// One target module whose identity matches the compiler-selected plan.
57#[derive(Debug)]
58pub struct AdmittedModule {
59    /// The target-native module image, identity already verified.
60    pub image: TargetModuleImage,
61    /// Canonical Program decoded from the module wire.
62    pub program: Arc<Program>,
63    /// Dispatch configuration carried by the payload entry.
64    pub config: DispatchConfig,
65}
66
67/// Admit a target payload against the artifact it claims to implement.
68///
69/// Every check here is a property of the neutral artifact and the payload
70/// envelope, so it holds identically for every backend. The returned modules
71/// are paired with their decoded Program and dispatch config, identity already
72/// verified; the caller decodes `image.bytes` in its own dialect.
73///
74/// # Errors
75///
76/// Returns `BackendError::UnsupportedFeature` when the payload format is not
77/// the one the materializer was acquired for, and `BackendError::InvalidProgram`
78/// when the payload is not authenticated for this artifact, its profile
79/// disagrees, or its module and entry counts do not match the compiler-selected
80/// fusion plan.
81pub fn admit(
82    artifact: &Artifact,
83    payload: &TargetPayload,
84    target: MaterializerTarget<'_>,
85) -> Result<Vec<AdmittedModule>, BackendError> {
86    if payload.neutral_artifact() != artifact.digest() {
87        return Err(invalid_module(
88            "target payload is not authenticated for the supplied neutral artifact",
89        ));
90    }
91    if payload.format() != target.format {
92        return Err(BackendError::UnsupportedFeature {
93            name: format!("target payload format `{}`", payload.format().identity()),
94            backend: target.backend_id.to_string(),
95        });
96    }
97    if payload.profile() != target.profile {
98        return Err(invalid_module(
99            "target payload profile does not match the acquired materializer profile",
100        ));
101    }
102
103    let bundle = TargetModuleBundle::from_bytes(payload.bytes())
104        .map_err(|error| compile_error(target.backend_id, error))?;
105    let selected = artifact.fusion();
106    if bundle.modules.len() != selected.len() {
107        return Err(invalid_module(
108            "target module count must equal the compiler-selected fusion-group count",
109        ));
110    }
111    if payload.entries().len() != selected.len() {
112        return Err(invalid_module(
113            "target entry count must equal the compiler-selected fusion-group count",
114        ));
115    }
116
117    let mut admitted = Vec::with_capacity(selected.len());
118    for ((image, record), entry) in bundle
119        .modules
120        .into_iter()
121        .zip(selected)
122        .zip(payload.entries())
123    {
124        admit_module_identity(&image, record)?;
125        if image.entry_point != "main" {
126            return Err(invalid_module("target module entry point must be `main`"));
127        }
128        if entry.name != image.entry_point {
129            return Err(invalid_module(
130                "target entry metadata must name the emitted target entry point",
131            ));
132        }
133        let program = Arc::new(Program::from_wire(&image.program).map_err(|error| {
134            invalid_module(&format!("selected Program is malformed: {error}"))
135        })?);
136        let mut config = DispatchConfig::default();
137        config.grid_override = Some(entry.grid_size);
138        config.dispatch_grid = Some(entry.grid_size);
139        admitted.push(AdmittedModule {
140            image,
141            program,
142            config,
143        });
144    }
145    Ok(admitted)
146}
147
148/// Reject a module whose identity disagrees with the neutral selected plan.
149fn admit_module_identity(
150    image: &TargetModuleImage,
151    record: &FusionRecord,
152) -> Result<(), BackendError> {
153    if image.group != record.id || image.stage != record.stage || image.nodes != record.members {
154        return Err(invalid_module(
155            "target module group/stage/node identity must match the neutral selected plan",
156        ));
157    }
158    Ok(())
159}
160
161/// Artifact resources sorted by lifetime, as an instance records them.
162pub struct ResourceProjection {
163    /// Every artifact resource by name.
164    pub values: BTreeMap<String, ArtifactValueId>,
165    /// Resources the artifact reports as outputs.
166    pub outputs: BTreeSet<ArtifactValueId>,
167    /// Resources the artifact retains across dispatches.
168    pub retained: BTreeSet<ArtifactValueId>,
169}
170
171/// Project an artifact's resources onto the three sets every instance keeps.
172///
173/// One pass over the resource records; the per-backend copies walked them
174/// three times to build the same three collections.
175#[must_use]
176pub fn project_resources(artifact: &Artifact) -> ResourceProjection {
177    let mut projection = ResourceProjection {
178        values: BTreeMap::new(),
179        outputs: BTreeSet::new(),
180        retained: BTreeSet::new(),
181    };
182    for resource in artifact.resources() {
183        projection
184            .values
185            .insert(resource.name.clone(), resource.value);
186        match resource.lifetime {
187            ResourceLifetime::Output => {
188                projection.outputs.insert(resource.value);
189            }
190            ResourceLifetime::Retained => {
191                projection.retained.insert(resource.value);
192            }
193            _ => {}
194        }
195    }
196    projection
197}