Skip to main content

Intents

Struct Intents 

Source
pub struct Intents {
    pub intents: Vec<IntentView>,
    pub findings: Vec<IntentFinding>,
}
Expand description

Every intent, derived, with every finding: what majordomus intent validate answers out of, and what the list, the record and the preflight are read from. Nothing here is stored.

use majordomus_cli::intent::Intents;
let empty = Intents { intents: vec![], findings: vec![] };
// a repository that declares no intent is valid, and says so
assert_eq!(empty.failures(), 0);
assert!(empty.intent("intent-lifecycle").is_none());

Fields§

§intents: Vec<IntentView>

Every intent, in identity order.

§findings: Vec<IntentFinding>

Every finding: per intent in identity order, then the milestones no intent serves.

Implementations§

Source§

impl Intents

Source

pub fn build(index: &Index, plan: &Plan, ev: &dyn EvidenceLookup) -> Intents

Derive every intent of an index against its plan and its evidence. Nothing is read but what the three already hold, and nothing is written.

The findings are the record’s own (this module) followed by the planning half’s (ADR 0073): whether the plan carries every criterion, why each issue exists, and whether the recorded gap and critique hold and were made before execution.

use majordomus_cli::index::Index;
use majordomus_cli::intent::{Intents, RepositoryEvidence};
use majordomus_cli::plan::Plan;
let plan = Plan::build(index);
let evidence = RepositoryEvidence::load(index).expect("the ledger is readable");
let intents = Intents::build(index, &plan, &evidence);
// the record's findings, then the coverage of its criteria by the plan
assert!(intents.failures() >= intents.findings.iter().filter(|f| f.level == "FAIL").count());
Source

pub fn coverage(index: &Index, plan: &Plan) -> IntentCoverage

The coverage of every criterion by the plan, and the reason every issue exists: the same derivation Intents::build reports findings from, answered on its own so a reader can ask which work carries which criterion (ADR 0073).

use majordomus_cli::index::Index;
use majordomus_cli::intent::Intents;
use majordomus_cli::plan::Plan;
let plan = Plan::build(index);
let coverage = Intents::coverage(index, &plan);
// every issue of the plan answers why it exists, including the maintenance ones
assert_eq!(coverage.issues.len(), plan.issues.len());
Source

pub fn derive( records: Vec<IntentRecord>, plan: &Plan, ev: &dyn EvidenceLookup, ) -> Intents

Derive from records already read: what Intents::build does after reading them, and what a test calls with records it wrote.

use majordomus_cli::evidence::TestId;
use majordomus_cli::intent::{
    ClaimStanding, EvidenceLookup, IntentEvidenceState, IntentRecord, Intents,
    TestStanding,
};
use majordomus_cli::plan::Plan;
struct NothingRecorded;
impl EvidenceLookup for NothingRecorded {
    fn test(&self, _: &TestId, _: &[String]) -> TestStanding {
        TestStanding { present: true, state: IntentEvidenceState::NotRun, proof: None }
    }
    fn claim(&self, _: &str) -> Option<ClaimStanding> { None }
    fn deployment(&self, _: &str) -> bool { false }
    fn object(&self, _: &str, _: &str) -> bool { false }
    fn file(&self, _: &str) -> bool { false }
}
let record = IntentRecord::from_metadata(
    ".ai/repo/project/intents/x.yaml",
    &serde_json::json!({"id": "x", "title": "X", "milestones": ["absent"],
        "satisfaction": [{"id": "c", "criterion": "c", "evidence": "test",
                          "ref": "test/cases/00_x.sh"}]}),
);
let intents = Intents::derive(vec![record], &plan, &NothingRecorded);
// the milestone it names is not in the plan, and that is a failure by name
assert!(intents.findings.iter().any(|f| f.code == "unknown_milestone"));
Source

pub fn intent(&self, id: &str) -> Option<&IntentView>

One intent by id, or None when this repository declares no such intent — which the capability turns into a refusal naming what it looked for.

use majordomus_cli::intent::Intents;
let intents = Intents { intents: vec![], findings: vec![] };
assert!(intents.intent("absent").is_none());
Source

pub fn failures(&self) -> usize

How many of the findings are failures rather than warnings: the count that decides whether the model is valid and whether intent validate exits 10.

use majordomus_cli::intent::Intents;
assert_eq!(Intents { intents: vec![], findings: vec![] }.failures(), 0);
Source

pub fn warnings(&self) -> usize

How many of the findings are warnings: reported, never fatal — a milestone no intent serves, an intent nobody has planned yet.

use majordomus_cli::intent::Intents;
assert_eq!(Intents { intents: vec![], findings: vec![] }.warnings(), 0);
Source

pub fn serving(&self, milestone: &str) -> Vec<&IntentView>

The intents that name a milestone, in identity order: the intents whose plan an issue under that milestone is part of, whatever it declares it serves.

use majordomus_cli::intent::Intents;
let intents = Intents { intents: vec![], findings: vec![] };
// a milestone no intent names carries maintenance work
assert!(intents.serving("fixture-milestone").is_empty());
Source§

impl Intents

Source

pub fn preflight( &self, plan: &Plan, gaps: &[GapRecord], critiques: &[CritiqueRecord], issue: Option<&str>, paths: &[String], ) -> IntentPreflight

Which intent work on issue, or on paths, serves; whether it is maintenance; or why it may not proceed. This is the one join a session or a transition consumes, answered on every surface by the intents.preflight capability.

use majordomus_cli::intent::{IntentPreflightCause, IntentPreflightVerdict, Intents};
use majordomus_cli::plan::Plan;
let intents = Intents { intents: vec![], findings: vec![] };
let answer = intents.preflight(&plan, &[], &[], Some("I0001"), &[]);
// an issue this plan does not hold is the first missing link, and it is named
assert_eq!(answer.verdict, IntentPreflightVerdict::Refused);
assert_eq!(answer.refusals[0].cause, IntentPreflightCause::UnknownIssue);
assert!(answer.refusal.unwrap().contains("I0001"));

An issue is followed through the criteria it declares in serves — never through its milestone alone — and each link is judged by the same coverage intent validate reports from, so every link validation fails is refused here too, and the preflight is at least as strict (it also refuses work whose only links point at retired intents): an issue that serves nothing while its milestone realises an intent, a criterion of an intent that does not name its milestone, a criterion or an intent that does not exist. An issue under milestones no live intent names, serving nothing, is maintenance. Every intent served must have a critique with no blocking finding open. Paths are followed to the open issues whose scope covers one, and every one of them is judged: one refused issue refuses the work.

Trait Implementations§

Source§

impl Clone for Intents

Source§

fn clone(&self) -> Intents

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Intents

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<'de> Deserialize<'de> for Intents

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl Eq for Intents

Source§

impl JsonSchema for Intents

Source§

fn schema_name() -> Cow<'static, str>

The name of the generated JSON Schema. Read more
Source§

fn schema_id() -> Cow<'static, str>

Returns a string that uniquely identifies the schema produced by this type. Read more
Source§

fn json_schema(generator: &mut SchemaGenerator) -> Schema

Generates a JSON Schema for this type. Read more
Source§

fn inline_schema() -> bool

Whether JSON Schemas generated for this type should be included directly in parent schemas, rather than being re-used where possible using the $ref keyword. Read more
Source§

impl PartialEq for Intents

Source§

fn eq(&self, other: &Intents) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl Serialize for Intents

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl StructuralPartialEq for Intents

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<T> DynClone for T
where T: Clone,

Source§

fn __clone_box(&self, _: Private) -> *mut ()

§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more