Expand description
The one writer of reasoning records, and the rules a record must satisfy before it becomes durable.
Records live under .ai/local/state/reasoning/<task>/, one JSON file per record,
written to a temporary name and renamed into place so that a reader never meets half a
record and two writers never share a file. They are checkout state (ADR 0005): never
tracked, never a source, never published.
Admission is where the design’s promises become refusals:
- a material assessment carries evidence — evidence before opinion;
- a plan is computed here, from the availability at this moment, never supplied;
- a consultation names an advisor its recorded plan selected — no review nobody planned, and no claim of review from an advisor that was not available (the plan’s own snapshot is the proof); a completed one carries a conclusion, a failed one none;
- a disagreement is settled by a resolution that cites evidence, and a conclusion is refused while a disagreement on its assessment is unsettled — there is no path from “two advisors said A” to a decision that skips the evidence;
- a conclusion on material uncertainty carries evidence and a validation plan, weighs every completed consultation of its assessment, and has its review count computed.
The lifecycle of a write: Store::load reads what is durable, admit checks the
input against it, redact removes secret shapes, mint_id names the record, and
Store::write makes it durable where the next Store::load finds it.
use majordomus_cli::reasoning::availability::{ModeResolution, ReasoningMode};
use majordomus_cli::reasoning::record::*;
use majordomus_cli::reasoning::store::{admit, mint_id, redact, Admission, Store};
let dir = tempfile::tempdir().unwrap();
let store = Store::at(dir.path());
let mode = ModeResolution { mode: ReasoningMode::Standard, source: "default".into() };
let admission = Admission { mode: &mode, availability: &[] };
let input = ReasoningInput::Assessment(AssessmentInput {
subject: "whether the cache survives a restart".into(),
..Default::default()
});
let (body, redacted) = redact(admit(input, &store.load(), &admission).unwrap());
let at = "2026-10-01T00:00:00Z";
let record = ReasoningRecord {
schema: RECORD_SCHEMA.into(),
version: RECORD_VERSION,
id: mint_id(body.kind(), at),
task: store.current_task(),
recorded_at: at.into(),
head: None,
redacted,
body,
};
store.write(&record).unwrap();
let loaded = store.load();
assert_eq!(loaded.records.len(), 1);
assert_eq!(loaded.records[0].task, "untasked");
assert!(loaded.get(&record.id).is_some());Structs§
- Admission
- What admission needs besides the records.
- Loaded
- The records of a store, read.
- Refusal
- Why a record was refused: one sentence a caller can act on.
- Store
- The store of one checkout: the one place reasoning records are read from and written to.
Constants§
- STATE_
DIR - The store’s directory, relative to the repository root.
- UNTASKED
- The task name of a record written while no task was open.
Functions§
- admit
- Admit an input against the records already durable: the body to store, or why not.
- assessment_
of - The assessment a record belongs to, when it belongs to one.
- mint_id
- A fresh record id: the kind, the stamp, and six hex digits of the moment and process.
- prior_
on_ subject - A standing conclusion on the same subject as an assessment, from any task: what a later session reuses instead of asking again.
- redact
- Remove every secret shape from every string of a body; the shapes that fired.
- resolution_
of - The resolution of a disagreement, when there is one.
- standing_
conclusion - The conclusion that stands for an assessment: its latest not superseded by another.
- strip_
controls - A text without control characters: ANSI escape sequences dropped whole, every other control character but the newline dropped.