Skip to content
Cockpit0.29.0
A snapshot: read at commit 707a04c7ce8 on 2026-10-18T00:06:01Z by majordomus 0.29.0. Nothing on this page is read again. See it live

project.no-screen-waits-for-a-source@1

A screen shows the latest reading of its sources at once, and never waits for a handler

What it is

URI
majordomus://rule/project.no-screen-waits-for-a-source@1
Kind
rule
Identity
project.no-screen-waits-for-a-source@1
Path
.ai/repo/rules/project/no-screen-waits-for-a-source.v1.md
Provenance
declared
Media type
text/markdown
As a capability
rule.project.no-screen-waits-for-a-source@1

Front matter

{
  "id": "project.no-screen-waits-for-a-source",
  "version": 1,
  "kind": "rule",
  "title": "A screen shows the latest reading of its sources at once, and never waits for a handler",
  "description": "A screen of the UI is rendered from the latest reading of each source it names, handed over from memory with the reading's age; a handler, git and the file system are touched by a worker behind the reader and never on the path of the request; a reading that is not of the repository as it is now says so and is replaced when the new one lands; and a capability's answer over the API, MCP and the command line stays exact.",
  "statement": "A screen of the UI MUST ask for the latest reading of a source (`Context::read`) and MUST NOT call a handler (`Context::execute`) on the path of a request; a reading that is stale or pending MUST be shown as stale or pending, with its age where it has one, and MUST NOT be drawn as current; and an answer given through `execute` MUST remain what the handler returns.",
  "status": "active",
  "class": "blocking",
  "depends_on": [
    "project.ui-derived-state@1",
    "project.cache-is-invisible@1",
    "project.interfaces-are-projections@1"
  ],
  "tags": [
    "ui",
    "performance",
    "cache",
    "derivation",
    "enforcement"
  ],
  "x-majordomus": {
    "tests": [
      "test/cases/1096_no_screen_waits_for_a_source.sh",
      "apps/majordomus-cli/tests/executor.rs"
    ]
  }
}

Content

---
id: project.no-screen-waits-for-a-source
version: 1
kind: rule
title: A screen shows the latest reading of its sources at once, and never waits for a handler
description: A screen of the UI is rendered from the latest reading of each source it names, handed over from memory with the reading's age; a handler, git and the file system are touched by a worker behind the reader and never on the path of the request; a reading that is not of the repository as it is now says so and is replaced when the new one lands; and a capability's answer over the API, MCP and the command line stays exact.
statement: A screen of the UI MUST ask for the latest reading of a source (`Context::read`) and MUST NOT call a handler (`Context::execute`) on the path of a request; a reading that is stale or pending MUST be shown as stale or pending, with its age where it has one, and MUST NOT be drawn as current; and an answer given through `execute` MUST remain what the handler returns.
status: active
class: blocking
depends_on: [project.ui-derived-state@1, project.cache-is-invisible@1, project.interfaces-are-projections@1]
tags: [ui, performance, cache, derivation, enforcement]

x-majordomus:
  tests: [test/cases/1096_no_screen_waits_for_a_source.sh, apps/majordomus-cli/tests/executor.rs]
---

# Rationale

On 2026-10-12 the owner called the UI "tragically slow" a day after it became the primary
surface. The measurements were plain. `/ui` took 2.2 to 2.5 s on every request, because
`health.report` runs probes and was part of the first paint. The first request after any
change of the repository took 5.6 to 8.1 s on three screens, because a cache keyed by the
repository's state is empty exactly then. One panel took 75.7 s. A cache had been added the
same day and worked wherever it applied.

The defect was not the cache. A page computed while a person waited, and a page costs its
slowest source. `project.cache-is-invisible` rightly forbids a cache from answering with a
value from another state of the repository, so no cache could close the gap. ADR 0142 takes
the computation off the request instead.

# Required behaviour

1. **A screen asks for readings.** Every source of a screen is read through
   `ui::source::ask`, `ask_all` or `ask_input`, which ask `Context::read`. Outside
   `ui/source.rs` and tests, nothing under `apps/majordomus-cli/src/ui` calls `execute`.
2. **A known source costs a lookup.** A source read in the repository as it is now is
   handed over from memory. Its handler runs on a worker of `capability::readings`, behind
   the caller.
3. **A moved repository is not waited for.** When the repository has moved, a caller waits
   for a new reading no longer than its patience (50 ms for a page) and is then handed the
   reading it has, marked stale.
4. **A reload is not waited for.** A screen is drawn from the generation the server has
   (`Live::view_without_waiting`). When the repository has moved past it, the screen says
   so and the next generation loads behind the reader.
5. **A reading says how it stands.** A stale or pending reading is shown as that, and a
   stale one with its age. Its source line carries `data-catching-up` until a current
   reading replaces it. A current reading older than five seconds says its age.
6. **An answer stays exact.** `execute` runs the handler or returns what the handler would
   return. Nothing a reading does changes what the API, MCP or the command line answer.
7. **It can be switched off.** `MAJORDOMUS_CAPABILITY_CACHE=off` makes a reading run its
   handler and wait for it.

# Failure behaviour

`test/cases/1096_no_screen_waits_for_a_source.sh` fails when a file under
`apps/majordomus-cli/src/ui` other than `source.rs` calls `execute` outside a test module,
when a served screen waits for its sources after the repository changed, or when a screen
that is catching up does not say so. The readings tests in
`apps/majordomus-cli/tests/executor.rs` fail when a known source is waited for, when a moved
repository is waited for past the patience, when two callers of one source run two
handlers, or when a failing or panicking source leaves no reading.

# Verification

```bash
MJ_TEST_JOBS=2 bash test/run.sh 1096_no_screen_waits_for_a_source
cd apps/majordomus-cli && cargo test --test executor
```

The latency budgets a screen is held to, and the gate that measures them, are I2489.