Expand description
The context compiler: what a development session should be given, derived from the repository rather than composed by hand.
§What this is for
A session that is handed a large hand-written prompt is handed somebody’s memory of the repository; a session that reads the repository from scratch on every request pays for discovery it has already paid for. This module is the third option: given an issue, a milestone, a free-text intent, some paths, or nothing at all, it derives the set of canonical objects that bear on the work, says why each one is in the set, says what it left out and why, and reports what the whole thing cost against a budget.
§It is not a second context system
majordomus context already assembles what a worker needs now: git, the active task,
its profile, the directory contracts over its scope, the open questions, the decisions,
the newest checkpoint, the most relevant handover, recent history — in authority order,
within a line budget, printing what it dropped. That command is the session briefing and
it stays the authority for it. What it cannot do is answer about a piece of work rather
than about the present moment, and its output is text: its own JSON projection carries
sections[] of {id, lines, text}, which is the assembled prose, not the selection.
So this module keeps the same authority order — Tier is that order applied to
objects instead of to sections — and changes three things:
- The unit is an object, not a section. Every entry carries the canonical identifier, the index’s own provenance, the selector that reached it, the reason, the confidence, the version and the cost. Nothing is flattened to text here; rendering a prompt is a projection of this value and lives downstream of it.
- It is keyed on the work. An issue, a milestone, an intent or a path, not only the session that happens to be open.
- It deduplicates and explains. The same ADR reached by four paths is one entry with four recorded discoveries, and the answer says which paths those were.
It also reuses rather than reimplements: the local records come from continuity.state,
the typed relations from crate::graph::COMPOSED — the repository’s own dependency
graph, where every reference the layer declares is already resolved — and the objects
from the index. There is no second relation table, no glob and no walk of the tree.
§The performance contract
Nothing here is built when a crate::capability::Context is composed. The compiler
runs inside its handler, over values already in memory, for the reason
crate::plan states about the plan: “App::load has a stated budget and
200 project records have no business inside it.” Deriving the composed graph over this
repository is milliseconds; building the index is seconds, and it is built once per
process. The answer carries the index fingerprint, so an answer is valid exactly as long
as the index it was computed from, and a caller can tell two trees apart without asking.
§A call, end to end
The whole module is three functions over one input type. compile answers what
should this session be given, explain answers why is this one thing in or out of
that, and policy answers by what rules — the last needing no request at all,
because the rules do not depend on what is being asked about.
The request below names nothing, which is the smallest legitimate one: the governance applies to every session whether or not anybody asked for it, so the answer is not empty.
use majordomus_cli::devcontext::{compile, explain, policy, CompileInput, ExplainInput};
use majordomus_cli::devcontext::{Standing, Tier};
use majordomus_cli::synthetic::SyntheticRepository;
let repo = SyntheticRepository::small().unwrap();
let ctx = repo.context().unwrap();
// what should a session here be given, with nothing asked for?
let compiled = compile(&ctx, CompileInput::default()).unwrap();
assert!(
compiled.selected.iter().any(|e| e.kind == "policy"),
"the governance applies without being asked for",
);
assert_eq!(compiled.budget.tiers.len(), Tier::ORDER.len());
// and why is that entry in it? — judged under the same request, so "excluded for
// budget" is a statement about a budget the caller can see
let first = compiled.selected[0].uri.clone();
let why = explain(&ctx, ExplainInput { uri: first.clone(), request: CompileInput::default() })
.unwrap();
assert_eq!(why.standing, Standing::Selected);
assert_eq!(why.uri, first);
assert!(why.entry.is_some() && !why.detail.is_empty());
// something the index does not hold is `unknown`, not an error
let absent = explain(
&ctx,
ExplainInput { uri: "majordomus://rule/nothing-like-this@1".into(), ..Default::default() },
)
.unwrap();
assert_eq!(absent.standing, Standing::Unknown);
// by what rules? — readable without a request, because they do not depend on one
let rules = policy(&ctx).unwrap();
assert_eq!(rules.tiers.len(), Tier::ORDER.len());
assert!(rules.edges.iter().any(|e| e.refused), "and it says what it will not follow");Re-exports§
pub use model::tokens_for;pub use model::Budget;pub use model::CommitReference;pub use model::CompiledContext;pub use model::Conflict;pub use model::ContextEntry;pub use model::Deduplicated;pub use model::Discovery;pub use model::EntryProvenance;pub use model::Excluded;pub use model::ExclusionReason;pub use model::GitContext;pub use model::Seed;pub use model::Selector;pub use model::Tier;pub use model::TierSpend;pub use model::BYTES_PER_TOKEN;pub use model::DEFAULT_BUDGET_TOKENS;pub use model::DEFAULT_MAX_DEPTH;pub use select::edge_policy;pub use select::intent_terms;pub use select::tier_for_kind;pub use select::EdgePolicy;
Modules§
- budget
- Deduplication, conflict, deterministic order, and what the budget could afford.
- model
- What a compiled development context is made of.
- select
- Which of the repository’s objects a request reaches, and by which declared path.
Structs§
- Compile
Input - What to compile a context about.
- Compiler
Policy - The compiler’s own rules, so that a caller reads the decision instead of inferring it from an answer.
- Edge
Rule - One edge of the composed graph, and what the compiler does with it.
- Explain
Input - The input of
devcontext.explain: one identifier, and the request to judge it under. - Explanation
- Why one identifier is, or is not, in a compiled context.
- Selector
Rule - One selector, and whether what it produces was declared or inferred.
- Tier
Rule - One tier, as the policy reports it: its place in the spend order, what it is for, and which kinds of object land in it.
Enums§
- Standing
- What one identifier’s standing in a compiled context is. Where one identifier stands with respect to a compiled context.
Constants§
- DEFAULT_
FLOOR - The lowest relevance the compiler offers unless the request says otherwise. Below it an entry is reached and reported as excluded rather than given.