Skip to content

The preflight

the preflight: what is proven about a checkout rather than what it is — a verdict per claim (git, episode, briefing, task, handover, policy, rules, ADRs, server and surfaces, peers, test runs, enforcement, projections, generated docs, deployment) with the evidence behind it; the nine verdicts, what entry reads and never reads, the measured cost, and what to run for each verdict

Rendered from docs/PREFLIGHT.md — the same Markdown GitHub shows.

Entering a Majordomus repository answers one question within the time a cd takes: is Majordomus actually in force here, what context am I working in, what integrations are alive, and which claims are currently proven? The answer is one typed value, environment::preflight::Preflight, built under apps/majordomus-cli/src/environment/preflight.rs. Every surface renders that value and none computes a status of its own. Behaviour as implemented and tested; where this document and the executable disagree, the document is wrong.

The rule is project.entry-reports-only-evidence (.ai/repo/rules/project/entry-reports-only-evidence.v1.md); the decision is ADR 0066.

Architecture

flowchart TD
  state["repository state<br/><small>git, .ai/local/state, lease, evidence ledger, gh-pages ref, index</small>"]
  observations["Observations<br/><small>plain data</small>"]
  preflight["Preflight<br/>environment.preflight<br/><small>sections of checks, each a verdict and its evidence</small>"]
  state -->|"observe(): the only reading; bounded, loopback only, never a build"| observations
  observations -->|"derive(): pure; every verdict is a test over a value"| preflight
  preflight --> enter["env enter<br/><small>the compact line drawn on entering (direnv, via .envrc)</small>"]
  preflight --> full["majordomus env preflight<br/><small>full, --compact, --format json, --full</small>"]
  preflight --> http["GET /api/v1/environment/preflight"]
  preflight --> mcp["MCP<br/><small>tool majordomus_preflight, resource majordomus://environment/preflight</small>"]
  preflight --> cockpit["Cockpit overview<br/><small>the Preflight card, each verdict as data-check / data-verdict</small>"]

RepositoryEnvironment (ENVIRONMENT.md) says what a checkout is. The preflight says what is proven about it. The two are separate values on purpose. Folding proof into the snapshot would change its digest, so every banner would read as news.

Repository bootstrap

.envrc is unchanged: it makes one call, bin/majordomus-env enter --shell direnv, and evaluates what that call exports (project.envrc-is-an-adapter). That call resolves the snapshot, ensures the runtime, and then draws the banner followed by the compact preflight, all from the same readings. A separate majordomus env preflight --compact line in .envrc would be a second git status on every cd, which the adapter rule forbids. The client bootstrap files (.mcp.json, .gemini/settings.json, .codex/config.toml) start the launcher and decide nothing.

Status semantics

VerdictMeansDrawn
verifiedproven against this tree by a recorded result or a direct answer✓
activein force now, observed directly, nothing recorded to verify✓
freshrecent enough to act on, against a declared threshold or the current commit✓
staleevidence exists, about another commit, tree or moment◐
degradedin force, in a form this executable would not serve◐
unavailablenothing is there to observe○
failedobserved, and it did not hold✗
unknownnobody looked, or the looking did not finish?
not_applicablenothing here to judge-

The first three cannot be produced without evidence. Check::new turns a bare claim of force into unknown, so no renderer can draw a success that nothing backs. attention lists every check that needs a look, the most urgent first: failed, degraded, stale, unavailable, unknown.

The checks

CheckEvidence readVerdicts
repository.gitgit status --porcelain=v2 --branch (the snapshot's own call)active, unavailable
session.episode.ai/local/state/session-current.yamlactive, degraded (another checkout's), unavailable
session.task.ai/local/state/current.yamlactive (outcome: active), not_applicable
session.contextthe episode's start_head and start_working_tree against HEAD, the tree and the task's startfresh, stale, unknown (no episode, or written over a dirty tree)
session.handovercontinuity's record resolution and session.freshnessfresh, stale, unknown, not_applicable
governance.policyLoadedPolicyactive, failed
governance.rulesrules.report, counted at a commitactive (at HEAD), stale, unknown
governance.adrsthe index, kind adractive (indexed; relevance not claimed), unknown
integration.serverthe lease, standing_of over one GET / — or, in the process that holds the lease, over its own lease document, so a rebuilt executable is degraded there tooverified, degraded (outdated), failed (stale lease), unavailable, unknown
integration.mcp / api / cockpitthe surfaces GET / lists with readyverified, degraded, failed, unavailable, unknown
integration.peersthis checkout's peer board (checkouts=this), the same board a served request readsactive, degraded, unavailable, unknown (not asked on entry)
verification.tests.ai/repo/evidence/ledger.json, each run judged by the evidence module's own tree comparison and the test's digestverified, stale, failed, unavailable
verification.coverage.ai/local/state/coverage/rust.json, the last whole-crate measurement scripts/rust-coverage ran itself, with the commit and tree it measuredverified (thresholds hold at HEAD), active (--report: measured at HEAD, nothing held), stale (another commit, or a tree that was not clean for the whole run), failed (a threshold, or the suite), unavailable (no record), unknown (unreadable)
verification.enforcementthe rule proofs of rules.reportverified, degraded, stale (another commit, or a tree that is not clean — checked before a failure), failed, not_applicable (nothing owes a proof), unknown
verification.projectionsprovider projections against their templatesverified, stale, unknown, not_applicable
verification.docs.ai/local/state/generation/check.json, the last verdict of scripts/pages current (the pre-commit hook's generation check: site data by input hash, registry projections by generate --check), recorded with the tree it checkedverified (that tree is HEAD's, the working tree clean, both halves current), failed (derived data was stale), stale (another tree, or a working tree that was not its index), unknown (no record, an unreadable one, or the registry half skipped)
verification.deploymentrefs/remotes/origin/gh-pages, whose commits name source: <sha>verified (source is HEAD, or a prefix of it), stale, unknown, unavailable

Governance status

A rule file on disk is discovered. governance.rules is active when rules.report counted the corpus at HEAD, which means it is loaded. Its summary gives how many rules are blocking, how many are the project's own and how many are vendored, and how many a CI gate runs. Enforced and verified belong to verification.enforcement. That check is verified only when every rule that owes an executable proof is proven against the tree. A gate that exists is not a verdict that passed, so a corpus that is gated and never run is degraded. ADRs are counted as indexed; nothing joins an ADR to a task, so none is claimed relevant.

Session context freshness

An episode's briefing is exact at the commit and tree it was written at. It is stale once HEAD moves, the tree changes under it, or a task starts after it. The summary names which of these happened, and majordomus context writes a current briefing. A briefing written over a dirty tree is unknown rather than fresh: the episode records the word dirty, not which changes, so an edit or a revert since cannot be seen. The preflight never regenerates context itself: entry is not the place for a write the provider's own lifecycle owns. No compiled context revision exists in a checkout yet, so none is shown.

MCP and Cockpit detection

A lease on disk is a claim, not a server. The server is verified only when the address the lease names answers GET / as this checkout's leaseholder, at this executable's version. That is lease::probe_reply, the same decision the launcher's election makes, with a 250 ms budget. A server that answers from other code is degraded. A lease whose address does not answer is failed. No lease is unavailable. The MCP, API and Cockpit checks read the ready flag the server's own index lists for each surface. The banner no longer marks a service answering unless the server is verified. MAJORDOMUS_URL is still exported, because a client can still reach the address. A served request holding the lease is its own evidence, and it reads its own peer board.

Verification evidence

A run in the evidence ledger verifies the tree only by the evidence module's definition of proven: it passed, its test still hashes as recorded, and the tree in front of you is the tree the run measured, with the ledger's own row excluded. A run at any other tree is stale. That comparison costs git two processes per recorded commit, so its answers are cached in .ai/local/state/environment/snapshot.json. The cache is keyed on HEAD, every path git reports changed, and the ledger file, so any change recomputes it. A served request never writes the cache. Coverage is reported unavailable until a coverage measurement leaves a record in the repository.

Deployment freshness

scripts/pages publishes to gh-pages, and every deployment commit names the source commit it was built from. The preflight reads the local ref refs/remotes/origin/gh-pages. The deployment is verified when that source is HEAD, stale when it is another commit, and unavailable without the ref. The ref is only as recent as the last fetch, and the evidence says so. Whether GitHub serves that commit is the business of scripts/pages verify. Local runtime state is never published to the static site.

Performance guarantees

Entry never builds the index. The rule tally comes from the cache that env preflight --full writes, stamped with the commit it was counted at. Entry never asks the peer board, which costs a round trip that gathers every checkout's board. It never runs a test, a build, the generator or a remote request. Its only socket is to the loopback address the lease names.

The measurement below was taken on 2026-09-15, debug build, in a linked worktree of this repository, while several other sessions were building on the same machine. It is warm entry through bin/majordomus-env enter --shell direnv, the call .envrc makes:

wall time
banner off (snapshot, runtime ensured, bridge)219–229 ms
compact banner and compact preflight248–301 ms
first entry after a change of HEAD or tree, ledger comparison recomputedabout 2.2 s once
env preflight (fast, asks the board)about 230 ms
env preflight --full (builds the index, counts the rule proofs)about 1.1 s

So the preflight adds about 30–70 ms to a warm entry. The floor under it is the entry that was already there. Every git process on this machine cost 40–90 ms under that load, and the ledger comparison is two of them per recorded commit, which is why its answers are cached. The mandate's targets of 50 ms warm, 150 ms cold and 250 ms hard are not met on this machine. The budgets the repository enforces are the policy's benchmark.budget.enter_ms (750 ms) and enter_cold_ms (1000 ms), measured by test/cases/190 on every run.

Troubleshooting

You seeIt meansDo
server ◐ degradeda server answers from another version or a replaced executablemajordomus serve stop && majordomus serve ensure
server ✗ failedthe lease names an address that does not answer as this checkoutmajordomus serve ensure
rules ? / enforced ?the rule corpus was never counted in this checkoutmajordomus env preflight --full
rules ◐counted at another commitmajordomus env preflight --full
tests ◐ stalethe recorded runs measured another treerun the tests and record them (majordomus evidence record)
context ◐ staleHEAD, the tree or the task moved since the briefingmajordomus context
deploy ◐ stalethe site was built from another commit, or the ref is not fetchedgit fetch origin gh-pages; scripts/pages verify
nothing drawna pipe, CI, or MAJORDOMUS_BANNER=offmajordomus env preflight

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