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
impl Intents
Sourcepub fn build(index: &Index, plan: &Plan, ev: &dyn EvidenceLookup) -> Intents
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());Sourcepub fn coverage(index: &Index, plan: &Plan) -> IntentCoverage
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());Sourcepub fn derive(
records: Vec<IntentRecord>,
plan: &Plan,
ev: &dyn EvidenceLookup,
) -> Intents
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"));Sourcepub fn intent(&self, id: &str) -> Option<&IntentView>
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());Sourcepub fn failures(&self) -> usize
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);Sourcepub fn warnings(&self) -> usize
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);Sourcepub fn serving(&self, milestone: &str) -> Vec<&IntentView>
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
impl Intents
Sourcepub fn preflight(
&self,
plan: &Plan,
gaps: &[GapRecord],
critiques: &[CritiqueRecord],
issue: Option<&str>,
paths: &[String],
) -> IntentPreflight
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<'de> Deserialize<'de> for Intents
impl<'de> Deserialize<'de> for Intents
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
impl Eq for Intents
Source§impl JsonSchema for Intents
impl JsonSchema for Intents
Source§fn schema_id() -> Cow<'static, str>
fn schema_id() -> Cow<'static, str>
Source§fn json_schema(generator: &mut SchemaGenerator) -> Schema
fn json_schema(generator: &mut SchemaGenerator) -> Schema
Source§fn inline_schema() -> bool
fn inline_schema() -> bool
$ref keyword. Read moreimpl StructuralPartialEq for Intents
Auto Trait Implementations§
impl Freeze for Intents
impl RefUnwindSafe for Intents
impl Send for Intents
impl Sync for Intents
impl Unpin for Intents
impl UnsafeUnpin for Intents
impl UnwindSafe for Intents
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.