Skip to content

devcontext.policy

What the compiler decides and how: the tiers in the order the budget spends in with the kinds that land in each, every edge kind the composed graph declares with the relevance multiplier the compiler follows it by in each direction — or the reason it refuses to follow it at all — the selectors with which of them infer rather than read, and the defaults for the budget, the depth and the relevance floor. Read this rather than inferring the policy from an answer.

What the compiler decides and how: the tiers in the order the budget spends in with the kinds that land in each, every edge kind the composed graph declares with the relevance multiplier the compiler follows it by in each direction — or the reason it refuses to follow it at all — the selectors with which of them infer rather than read, and the defaults for the budget, the depth and the relevance floor. Read this rather than inferring the policy from an answer.

Exposure

Where this one definition is reachable. Absence is explicit: a surface not listed does not carry it.

surfaceas
MCPtool majordomus_devcontext_policy
resource majordomus://devcontext/policy
HTTPGET /api/v1/devcontext/policy operationId devcontext.policy
command linemajordomus devcontext policy

Schemas

The canonical input and output, from the Rust types; the MCP tool schema and the OpenAPI parameters and responses are derived from these.

input · Empty

No input.

No properties: the capability takes no input.

JSON Schema
{
  "additionalProperties": false,
  "description": "No input.",
  "title": "Empty",
  "type": "object"
}

output · CompilerPolicy

The compiler's own rules, so that a caller reads the decision instead of inferring it from an answer.

This is the answer to "why did I get that", asked once rather than reverse-engineered from every context. It is a projection of the tables and constants this module is built from — Tier::ORDER, select::EDGES, Selector::ALL and the four defaults — and holds no numbers of its own, so the published rules and the code that applies them cannot drift apart.

The defaults are here because they are what a request gets when it says nothing, and a caller tuning a request needs to know what it is tuning away from.

use majordomus_cli::devcontext::{policy, CompilerPolicy, Selector, Tier};
use majordomus_cli::devcontext::{BYTES_PER_TOKEN, DEFAULT_BUDGET_TOKENS};
use majordomus_cli::devcontext::{DEFAULT_FLOOR, DEFAULT_MAX_DEPTH};
use majordomus_cli::graph;
use majordomus_cli::synthetic::SyntheticRepository;

let repo = SyntheticRepository::small().unwrap();
let ctx = repo.context().unwrap();
let rules: CompilerPolicy = policy(&ctx).unwrap();

// it names the graph it reads relations from, rather than leaving it to be guessed
assert_eq!(rules.schema, 1);
assert_eq!(rules.graph, graph::COMPOSED);

// the three tables are complete
assert_eq!(rules.tiers.len(), Tier::ORDER.len());
assert_eq!(rules.selectors.len(), Selector::ALL.len());
assert!(!rules.edges.is_empty());

// and the published defaults are the constants a silent request actually gets
assert_eq!(rules.default_budget_tokens, DEFAULT_BUDGET_TOKENS);
assert_eq!(rules.default_max_depth, DEFAULT_MAX_DEPTH);
assert_eq!(rules.default_floor, DEFAULT_FLOOR);
assert_eq!(rules.bytes_per_token, BYTES_PER_TOKEN);
propertytyperequireddescription
bytes_per_token integer yes Bytes per estimated token.
default_budget_tokens integer yes The default ceiling in estimated tokens.
default_floor number yes The default relevance floor.
default_max_depth integer yes The default depth limit.
edges array yes Every edge kind the composed graph has, followed or refused.
graph string yes The graph the relations are read from.
schema integer yes The format of this answer.
selectors array yes The selectors, and which of them infer.
tiers array yes The tiers, in the order the budget spends in.
JSON Schema
{
  "$defs": {
    "EdgeRule": {
      "description": "One edge of the composed graph, and what the compiler does with it.\n\nEvery edge kind the graph declares gets a row, followed or not, which is the property\nthat makes this projection worth reading: an edge added to the graph and not to the\ntraversal table appears here as `refused` with a reason saying the compiler has no rule\nfor it, rather than being silently unfollowed. A table that only listed the edges it\nfollowed could not tell you what it was ignoring.\n\n`forward` and `reverse` are absent rather than zero when the edge is not followed that\nway, so \"not followed\" is one representation and not two. `means` is the graph's own\naccount of the relation; `reason` is this compiler's account of why it is or is not\ncontext, in both directions.\n\n```\nuse majordomus_cli::devcontext::{edge_policy, policy, EdgeRule};\nuse majordomus_cli::synthetic::SyntheticRepository;\n\nlet repo = SyntheticRepository::small().unwrap();\nlet ctx = repo.context().unwrap();\nlet rules = policy(&ctx).unwrap();\n\n// one row per edge kind the graph declares, followed or refused\nlet edges: &[EdgeRule] = &rules.edges;\nassert!(!edges.is_empty(), \"the graph declares edges\");\nfor e in edges {\n    // the row always says what the relation is and what was decided about it\n    assert!(!e.means.is_empty() && !e.reason.is_empty(), \"{}\", e.edge);\n\n    if e.refused {\n        // not followed in either direction, and absent rather than zero\n        assert!(e.forward.is_none() && e.reverse.is_none(), \"{}\", e.edge);\n        assert!(edge_policy(&e.edge).is_none(), \"{} is refused and in the table\", e.edge);\n    } else {\n        // followed at least one way, at a weight the table declares\n        assert!(e.forward.is_some() || e.reverse.is_some(), \"{}\", e.edge);\n        let p = edge_policy(&e.edge).expect(\"a followed edge has a policy\");\n        assert_eq!(e.forward, (p.forward > 0.0).then_some(p.forward));\n        assert_eq!(e.reverse, (p.reverse > 0.0).then_some(p.reverse));\n    }\n}\n```",
      "properties": {
        "edge": {
          "description": "The edge kind, as the composed graph names it.",
          "type": "string"
        },
        "forward": {
          "description": "The relevance multiplier when followed source to target; absent when refused.",
          "format": "double",
          "type": [
            "number",
            "null"
          ]
        },
        "means": {
          "description": "What the graph asserts by it.",
          "type": "string"
        },
        "reason": {
          "description": "Why the target is context for the source, or why the edge is refused.",
          "type": "string"
        },
        "refused": {
          "description": "True when the compiler will not follow it in either direction.",
          "type": "boolean"
        },
        "reverse": {
          "description": "The multiplier when followed target to source; absent when refused.",
          "format": "double",
          "type": [
            "number",
            "null"
          ]
        }
      },
      "required": [
        "edge",
        "means",
        "reason",
        "refused"
      ],
      "type": "object"
    },
    "Selector": {
      "description": "What reached an entry. This is the provenance of the *selection*, and it is a different\nfact from the provenance of the file: `Relation` says the compiler followed an edge the\nlayer declares, `IntentMatch` says it guessed from words. An answer that did not keep\nthem apart could not say which half of itself to trust.\n\nThe division that matters is `Selector::declared`, and it is deliberately lopsided:\nsix of the seven selectors follow something the repository states, and exactly one\nguesses. That ratio is the design. Inference is confined to a single selector so that\nthe inferred part of any answer can be found, weighed and ignored, rather than being\nmixed through the rest at unmarked strength.\n\n```\nuse majordomus_cli::devcontext::Selector;\n\n// exactly one selector infers, and the answer can always be split on it\nlet inferred: Vec<&str> = Selector::ALL\n    .iter()\n    .filter(|s| !s.declared())\n    .map(|s| s.as_str())\n    .collect();\nassert_eq!(inferred, [\"intent_match\"]);\n\n// every selector has its own word, so a reason is never ambiguous\nlet mut words: Vec<&str> = Selector::ALL.iter().map(|s| s.as_str()).collect();\nlet before = words.len();\nwords.sort();\nwords.dedup();\nassert_eq!(words.len(), before);\n\n// and the word is the serialised form\nassert_eq!(\n    serde_json::to_value(Selector::ScopePath).unwrap(),\n    serde_json::json!(\"scope_path\"),\n);\n```",
      "oneOf": [
        {
          "const": "seed",
          "description": "Named in the request.",
          "type": "string"
        },
        {
          "const": "relation",
          "description": "Reached along a typed edge of the composed graph.",
          "type": "string"
        },
        {
          "const": "scope_path",
          "description": "Its path lies under a path the request or a seed declares.",
          "type": "string"
        },
        {
          "const": "contract",
          "description": "A directory contract that reaches one of those paths.",
          "type": "string"
        },
        {
          "const": "governance",
          "description": "A rule or policy the layer applies to everything.",
          "type": "string"
        },
        {
          "const": "session_state",
          "description": "A recorded session of this branch or of these paths, the handover the resolver\nchose, the newest checkpoint.",
          "type": "string"
        },
        {
          "const": "intent_match",
          "description": "Inferred: the words of the intent occur in the object's own words.",
          "type": "string"
        }
      ]
    },
    "SelectorRule": {
      "description": "One selector, and whether what it produces was declared or inferred.\n\nTwo fields, and the second is the whole reason the projection exists: a caller consuming\na compiled context needs to know which selectors it can trust as repository fact, and\nderiving that from the answer would mean inferring it from confidence values. Published\nhere, it is a rule rather than a pattern a reader noticed.\n\n```\nuse majordomus_cli::devcontext::{policy, Selector, SelectorRule};\nuse majordomus_cli::synthetic::SyntheticRepository;\n\nlet repo = SyntheticRepository::small().unwrap();\nlet ctx = repo.context().unwrap();\nlet rules = policy(&ctx).unwrap();\n\n// every selector is published, and each row agrees with the selector it names\nlet selectors: &[SelectorRule] = &rules.selectors;\nassert_eq!(selectors.len(), Selector::ALL.len());\nfor r in selectors {\n    assert_eq!(r.declared, r.selector.declared());\n}\n\n// and the inferring one is named, so the guessed half of an answer can be found\nlet inferred: Vec<Selector> =\n    selectors.iter().filter(|r| !r.declared).map(|r| r.selector).collect();\nassert_eq!(inferred, [Selector::IntentMatch]);\n```",
      "properties": {
        "declared": {
          "description": "Declared by the repository, or inferred by the compiler.",
          "type": "boolean"
        },
        "selector": {
          "$ref": "#/$defs/Selector",
          "description": "The selector."
        }
      },
      "required": [
        "selector",
        "declared"
      ],
      "type": "object"
    },
    "Tier": {
      "description": "Where an entry sits in the order the budget spends in.\n\nThe order is this repository's own: `lib/context.sh` assembles its sections \"in\nauthority order, highest first, because a worker that runs out of budget must lose the\nleast reliable evidence rather than the most: git, then the task and its policy, then\nblockers, then authored records, then event history.\" These six tiers are that\nsentence, applied to objects instead of to sections.\n\nThe derived `Ord` is load-bearing: the variants are declared in authority order, so\n`<` means \"spent before\" and \"harder to drop\", and the budget's ordering is a plain\n`sort` rather than a table mapping tiers to ranks. A variant added in the wrong place\nwould silently re-rank the whole answer, which is why the declaration order is the one\nthing about this enum to be careful with.\n\n```\nuse majordomus_cli::devcontext::Tier;\n\n// the declaration order *is* the order the budget spends in\nlet mut sorted = Tier::ORDER.to_vec();\nsorted.sort();\nassert_eq!(sorted, Tier::ORDER.to_vec());\n\n// so the strongest authority is the smallest, and it is the one never dropped\nassert_eq!(Tier::ORDER.iter().copied().min(), Some(Tier::Task));\nassert!(Tier::Task < Tier::Governance && Tier::Governance < Tier::History);\n\n// and the serialised word is the lowercase one the report is read under\nassert_eq!(\n    serde_json::to_value(Tier::Governance).unwrap(),\n    serde_json::json!(Tier::Governance.as_str()),\n);\n```",
      "oneOf": [
        {
          "const": "task",
          "description": "What was asked for: the issue, its milestone, the paths named, the intent. Never\ndropped — a context that lost the thing it was compiled about is not a smaller\nanswer, it is the wrong one.",
          "type": "string"
        },
        {
          "const": "governance",
          "description": "What the work will be judged against: the policy, the scope, the directory\ncontracts that reach the named paths, and the rules. A blocking rule is never\ndropped.",
          "type": "string"
        },
        {
          "const": "source",
          "description": "The code and the cases the work touches.",
          "type": "string"
        },
        {
          "const": "decision",
          "description": "The architectural decisions already in force over it.",
          "type": "string"
        },
        {
          "const": "knowledge",
          "description": "What a previous session left: handovers, session records, curated knowledge.",
          "type": "string"
        },
        {
          "const": "history",
          "description": "Supporting evidence: use cases, claims, features, and the rest of the layer.",
          "type": "string"
        }
      ]
    },
    "TierRule": {
      "description": "One tier, as the policy reports it: its place in the spend order, what it is for, and\nwhich kinds of object land in it.\n\n`position` is 1-based and exists because the wire form has no inherent order a consumer\ncan rely on — the `Tier` enum's `Ord` is a Rust fact, not a JSON one — so the rank is\nmade explicit for the readers that are not this crate. `kinds` is the inverse of\n`tier_for_kind`, published so that a caller can see where a kind will land without\ncompiling an answer and looking.\n\n```\nuse majordomus_cli::devcontext::{policy, tier_for_kind, Tier, TierRule};\nuse majordomus_cli::synthetic::SyntheticRepository;\n\nlet repo = SyntheticRepository::small().unwrap();\nlet ctx = repo.context().unwrap();\nlet rules = policy(&ctx).unwrap();\n\n// the first tier spent is the one that is never dropped, at position 1\nlet first: &TierRule = &rules.tiers[0];\nassert_eq!(first.tier, Tier::Task);\nassert_eq!(first.position, 1, \"1-based, so the order survives serialisation\");\n\n// every tier is reported, in the order the budget spends in, and explains itself\nassert_eq!(rules.tiers.len(), Tier::ORDER.len());\nfor (i, r) in rules.tiers.iter().enumerate() {\n    assert_eq!(r.position, i + 1);\n    assert_eq!(r.meaning, r.tier.meaning());\n}\n\n// and every kind is listed under the tier the classifier puts it in, exactly once —\n// so the published table and the function behind it cannot disagree\nlet mut listed = 0usize;\nfor r in &rules.tiers {\n    for kind in &r.kinds {\n        assert_eq!(tier_for_kind(kind), r.tier, \"{kind} is listed under the wrong tier\");\n        listed += 1;\n    }\n}\nlet mut all: Vec<&str> = rules.tiers.iter().flat_map(|r| &r.kinds).map(String::as_str).collect();\nall.sort();\nall.dedup();\nassert_eq!(all.len(), listed, \"a kind is listed under one tier only\");\n```",
      "properties": {
        "kinds": {
          "description": "The kinds of object that land in it.",
          "items": {
            "type": "string"
          },
          "type": "array"
        },
        "meaning": {
          "description": "What it is for.",
          "type": "string"
        },
        "position": {
          "description": "Its position in the order the budget spends in; 1 is spent first.",
          "format": "uint",
          "minimum": 0,
          "type": "integer"
        },
        "tier": {
          "$ref": "#/$defs/Tier",
          "description": "The tier."
        }
      },
      "required": [
        "tier",
        "position",
        "meaning",
        "kinds"
      ],
      "type": "object"
    }
  },
  "description": "The compiler's own rules, so that a caller reads the decision instead of inferring it\nfrom an answer.\n\nThis is the answer to \"why did I get that\", asked once rather than reverse-engineered\nfrom every context. It is a projection of the tables and constants this module is built\nfrom — `Tier::ORDER`, `select::EDGES`, `Selector::ALL` and the four defaults\n— and holds no numbers of its own, so the published rules and the code that applies them\ncannot drift apart.\n\nThe defaults are here because they are what a request gets when it says nothing, and a\ncaller tuning a request needs to know what it is tuning away from.\n\n```\nuse majordomus_cli::devcontext::{policy, CompilerPolicy, Selector, Tier};\nuse majordomus_cli::devcontext::{BYTES_PER_TOKEN, DEFAULT_BUDGET_TOKENS};\nuse majordomus_cli::devcontext::{DEFAULT_FLOOR, DEFAULT_MAX_DEPTH};\nuse majordomus_cli::graph;\nuse majordomus_cli::synthetic::SyntheticRepository;\n\nlet repo = SyntheticRepository::small().unwrap();\nlet ctx = repo.context().unwrap();\nlet rules: CompilerPolicy = policy(&ctx).unwrap();\n\n// it names the graph it reads relations from, rather than leaving it to be guessed\nassert_eq!(rules.schema, 1);\nassert_eq!(rules.graph, graph::COMPOSED);\n\n// the three tables are complete\nassert_eq!(rules.tiers.len(), Tier::ORDER.len());\nassert_eq!(rules.selectors.len(), Selector::ALL.len());\nassert!(!rules.edges.is_empty());\n\n// and the published defaults are the constants a silent request actually gets\nassert_eq!(rules.default_budget_tokens, DEFAULT_BUDGET_TOKENS);\nassert_eq!(rules.default_max_depth, DEFAULT_MAX_DEPTH);\nassert_eq!(rules.default_floor, DEFAULT_FLOOR);\nassert_eq!(rules.bytes_per_token, BYTES_PER_TOKEN);\n```",
  "properties": {
    "bytes_per_token": {
      "description": "Bytes per estimated token.",
      "format": "uint64",
      "minimum": 0,
      "type": "integer"
    },
    "default_budget_tokens": {
      "description": "The default ceiling in estimated tokens.",
      "format": "uint64",
      "minimum": 0,
      "type": "integer"
    },
    "default_floor": {
      "description": "The default relevance floor.",
      "format": "double",
      "type": "number"
    },
    "default_max_depth": {
      "description": "The default depth limit.",
      "format": "uint",
      "minimum": 0,
      "type": "integer"
    },
    "edges": {
      "description": "Every edge kind the composed graph has, followed or refused.",
      "items": {
        "$ref": "#/$defs/EdgeRule"
      },
      "type": "array"
    },
    "graph": {
      "description": "The graph the relations are read from.",
      "type": "string"
    },
    "schema": {
      "description": "The format of this answer.",
      "format": "uint64",
      "minimum": 0,
      "type": "integer"
    },
    "selectors": {
      "description": "The selectors, and which of them infer.",
      "items": {
        "$ref": "#/$defs/SelectorRule"
      },
      "type": "array"
    },
    "tiers": {
      "description": "The tiers, in the order the budget spends in.",
      "items": {
        "$ref": "#/$defs/TierRule"
      },
      "type": "array"
    }
  },
  "required": [
    "schema",
    "graph",
    "tiers",
    "edges",
    "selectors",
    "default_budget_tokens",
    "default_max_depth",
    "default_floor",
    "bytes_per_token"
  ],
  "title": "CompilerPolicy",
  "type": "object"
}

Policies

benchmark
required — a target on every transport the exposure declares; the cases are the input type's
cache
disabled — every call runs the handler

Benchmark targets

Derived from the registry for this repository: one requirement per transport, and the cases the input type provides. The whole matrix is on the benchmarks page.

transportstatecasestargets
directcovered1default
mcpcovered1default
httpcovered1default

Searches the titles and descriptions of every page this site publishes.