Docs

action-policy

Source: crates/lvcs-action/src/policy.rs.

/// A counted set of attestations of one frontier.
///
/// They all name `frontier`, `toolchain_hash`, and `actions`, and come from
/// the distinct runner keys `runners`, at most one per runner key
/// and one per device. `runners.len()` is the set's size, which
/// `channel.read` reports.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Counted {
    /// The frontier every attestation names.
    pub frontier: FrontierId,
    /// The toolchain hash every attestation names.
    pub toolchain_hash: [u8; 32],
    /// The actions, with their inputs, every attestation names.
    pub actions: BTreeMap<ActionId, InputsHash>,
    /// The runner keys whose attestations count.
    pub runners: BTreeSet<ParticipantKey>,
}

/// The largest counted set among `attestations` (of one frontier, from one
/// channel), when it reaches `threshold`.
///
/// It holds at most one attestation per runner key and at most one per
/// device, all naming the same frontier id, `toolchain_hash`, and `actions`
/// map, and that map holding every action in `required` (every change
/// action but the generator at `lvcs.toml`'s approved heads, decisions 127
/// and 245). An
/// attestation whose frontier holds an override or workspace document
/// counts toward nothing. `None` when no set reaches `threshold`. Equal
/// attestations count once, so concurrent puts of one entry never count
/// twice. Among sets of the largest size, the one whose frontier id, then
/// `toolchain_hash`, then `actions` sorts first is chosen; its `runners`
/// are a maximum matching of runner keys to devices, found in key
/// order, so every peer reports the same set for the same attestations.
#[must_use]
pub fn counted(
    attestations: &[Attestation],
    required: &BTreeSet<ActionId>,
    threshold: u32,
) -> Option<Counted> {
    largest(attestations, required).filter(|set| reaches(set, threshold))
}

/// What one derivation's records for one `InputsHash` come to (row 180).
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub enum GenerationState {
    /// At least the threshold of runners' records agree on every
    /// output digest, and no record differs or failed.
    Counted,
    /// Two records name different output digests: never counts.
    Diverged,
    /// A record failed: never counts.
    Failed,
}

/// The state of one `(derive, inputs)`'s records, and the record that
/// stands for it.
///
/// For `Counted`, `record` is the least runner key's record (the
/// records all agree on every output digest; their heads may differ). For
/// `Failed`, it is the least runner key's failed record. For
/// `Diverged`, it is the least runner key's record among those whose
/// digests differ from the least runner key's record.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct GenerationCount<'a> {
    /// What the records come to.
    pub state: GenerationState,
    /// The record that stands for it.
    pub record: &'a Generation,
}

/// What `records`, every record of one derivation for one `InputsHash`,
/// come to under `threshold` (row 180, decision 120's rule).
///
/// A failed record makes them `Failed`, and two records whose output
/// digests differ make them `Diverged`; neither ever counts, so a later
/// contradicting record un-counts them. Otherwise they are `Counted` when
/// a maximum matching of their runner keys to their devices (at most
/// one record per key and one per device, as [`counted`] has it) reaches
/// `threshold`. `None` when there is no record, or the agreeing records
/// don't reach `threshold`. Records are ordered by runner key, then
/// device, then signature, so every peer picks the same record for the
/// same records.
#[must_use]
pub fn generation(records: &[Generation], threshold: u32) -> Option<GenerationCount<'_>> {
    let mut ordered: Vec<&Generation> = records.iter().collect();
    ordered.sort_by_key(|record| record_order(record));
    let first = *ordered.first()?;
    if let Some(failed) = ordered.iter().find(|record| record.failure.is_some()) {
        return Some(GenerationCount {
            state: GenerationState::Failed,
            record: failed,
        });
    }
    let agreed = digests(first);
    if let Some(differing) = ordered.iter().find(|record| digests(record) != agreed) {
        return Some(GenerationCount {
            state: GenerationState::Diverged,
            record: differing,
        });
    }
    let pairs: BTreeSet<(ParticipantKey, DeviceKey)> = ordered
        .iter()
        .map(|record| (record.runner, record.device))
        .collect();
    let runners = u32::try_from(matching(&pairs).len()).unwrap_or(u32::MAX);
    (runners >= threshold).then_some(GenerationCount {
        state: GenerationState::Counted,
        record: first,
    })
}