Skip to main content

Module devcontext

Module devcontext 

Source
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§

CompileInput
What to compile a context about.
CompilerPolicy
The compiler’s own rules, so that a caller reads the decision instead of inferring it from an answer.
EdgeRule
One edge of the composed graph, and what the compiler does with it.
ExplainInput
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.
SelectorRule
One selector, and whether what it produces was declared or inferred.
TierRule
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.

Functions§

compile
Compile a context. The one entry point; every projection calls this.
explain
Why one identifier is or is not in the context a request compiles to.
policy
The compiler’s rules: the tiers, every edge of the composed graph and what is done with it, the selectors, and the defaults.