Skip to main content

khive_fold/
pipeline.rs

1//! ComposePipeline: score candidates then pack to budget.
2
3use crate::anchor::{Anchor, AnchorGraph};
4use crate::error::FoldError;
5use crate::objective::{Objective, ObjectiveContext};
6use crate::selector::{Selector, SelectorInput, SelectorOutput, SelectorWeights};
7
8/// Pipeline that scores candidates with an objective then packs to budget via a selector.
9pub struct ComposePipeline<T> {
10    /// Graph anchor used for causal provenance traversal before scoring.
11    pub anchor: Box<dyn Anchor>,
12    /// Objective that assigns scores to each candidate.
13    pub objective: Box<dyn Objective<T>>,
14    /// Selector that packs the scored candidates under a budget.
15    pub selector: Box<dyn Selector<T>>,
16}
17
18impl<T: Clone + Send + Sync + 'static> ComposePipeline<T> {
19    /// Score candidates with the objective, then pack under budget with the selector.
20    pub fn execute(
21        &self,
22        _graph: &AnchorGraph,
23        candidates: Vec<SelectorInput<T>>,
24        budget: usize,
25        weights: &SelectorWeights,
26        context: &ObjectiveContext,
27    ) -> Result<SelectorOutput<T>, FoldError> {
28        let scored = candidates
29            .into_iter()
30            .map(|mut candidate| {
31                candidate.score = self.objective.score(&candidate.content, context) as f32;
32                candidate
33            })
34            .collect();
35        self.selector.select(scored, budget, weights)
36    }
37}