Skip to main content

Module state

Module state 

Source
Expand description

The reasoning state of a session, derived from its records and nothing else: what is uncertain, what was asked and what came back, where advice disagreed and what settled it, what was concluded and whether it was proven — plus the timeline, the degradation that happened along the way, and the report a handover or a final summary carries.

Deterministic: the records are read in (recorded_at, id) order, every list here keeps that order, and the report is rendered from these lists alone. The same records give the same state on every surface, which is what lets the CLI, HTTP, MCP, the Cockpit, majordomus context and a handover all say the same thing.

The lifecycle: records are admitted and stored, derive() turns them into a ReasoningState, and render_markdown turns that state into the paragraph a handover carries. explain answers for one record with its whole chain.

use majordomus_cli::reasoning::availability::{ModeResolution, ReasoningMode};
use majordomus_cli::reasoning::record::*;
use majordomus_cli::reasoning::state::{derive, explain, render_markdown, AssessmentStanding};
use majordomus_cli::reasoning::store::{admit, Admission, Loaded};

let mode = ModeResolution { mode: ReasoningMode::Standard, source: "default".into() };
let admission = Admission { mode: &mode, availability: &[] };
let mut loaded = Loaded::default();
let add = |loaded: &mut Loaded, input: ReasoningInput| {
    let body = admit(input, loaded, &admission).unwrap();
    let n = loaded.records.len() + 1;
    let id = format!("{}-{n}", body.kind());
    loaded.records.push(ReasoningRecord {
        schema: RECORD_SCHEMA.into(),
        version: RECORD_VERSION,
        id: id.clone(),
        task: "t".into(),
        recorded_at: format!("2026-10-01T00:00:{n:02}Z"),
        head: None,
        redacted: vec![],
        body,
    });
    id
};

let a = add(&mut loaded, ReasoningInput::Assessment(AssessmentInput {
    subject: "whether the cache survives a restart".into(),
    ..Default::default()
}));
add(&mut loaded, ReasoningInput::Plan(PlanInput { assessment: a.clone() }));
let k = add(&mut loaded, ReasoningInput::Conclusion(ConclusionInput {
    assessment: a.clone(),
    decision: "rebuild the cache on start".into(),
    rationale: "nothing persists it".into(),
    ..Default::default()
}));
add(&mut loaded, ReasoningInput::Validation(ValidationInput {
    conclusion: k.clone(),
    check: "a restarted worker rebuilds it".into(),
    command: None,
    outcome: ValidationOutcome::Pass,
    evidence: vec![],
}));

let state = derive(&loaded, Some("t"));
assert_eq!(state.assessments[0].standing, AssessmentStanding::Validated);
assert_eq!(state.timeline.len(), 4);
let report = render_markdown(&state);
assert!(report.contains("- Decision conclusion-3: rebuild the cache on start"));
assert_eq!(explain(&loaded, &k).unwrap().chain.len(), 4);

Structs§

AssessmentView
One assessment and where it stands.
ConclusionView
One conclusion, as the state reports it.
ConsultationView
One consultation, as the state reports it.
DisagreementView
One disagreement, as the state reports it.
ReasoningExplanation
A record with everything it rests on and everything that rests on it.
ReasoningState
The reasoning state of a task (or of every task).
ReasoningStep
One step of the timeline: when, which record, which phase, and one line saying what happened.
ReasoningTotals
Totals over the records of the derived task: counts, reviewers and reported tokens.

Enums§

AssessmentStanding
Where an assessment stands, from open through validated.
ReasoningPhase
A phase of the reasoning timeline.

Functions§

derive
Derive the state of task (None for every task).
explain
Explain one record: its assessment and the whole chain of that assessment.
render_markdown
The state as Markdown: what a handover carries and a final report ends with. Empty when there is nothing to say.