Skip to content

surfaces-never-disagree — Every surface projects the same state, says when it was observed, and keeps no list of its own

A reader on any surface sees the same value, the time it was observed and whether it is stale; a capability added to or removed from the registry appears or disappears everywhere with no consumer edit; a page served beside the write routes runs only script it shipped.

ACTIVE 7 of 13 issues done

ready
6
blocked
0
active
0
verify
0
done
7
cancelled
0

Problem

The core projection holds: the live server's 181 /api/v1 routes equal the 181 OpenAPI operations, which equal the committed docs/generated/openapi.json, and the executor is the only dispatch path (apps/majordomus-cli/src/capability/executor.rs:156). Around it: freshness is not uniform, since dashboard/overview, episodes, lifecycle/runtime, plan/status, served and mesh carry no observed_at, the overview badge is permanently stale on an idle repository (apps/majordomus-cli/src/index.rs:44, apps/majordomus-cli/src/live.rs:250-252) and GET / said stale: null while serving a build 12 commits behind HEAD. The parity property compares HTTP only for GET routes and excludes the coordination read models (apps/majordomus-cli/tests/properties.rs:166-168,300), and nothing compares CLI JSON with HTTP. /swagger has no CSP and no SRI on the same origin as the write routes (apps/majordomus-cli/src/http/swagger.rs:52,79). The Cockpit and the site keep at least nine consumer-side catalogues of what the registry declares, and ADR 0004 says nothing has a second registry. Measured in the runtime baseline audit of 2026-10-09 at master 1fb8d6be44 (plan/RUNTIME_BASELINE.md).

Outcome

A reader on any surface sees the same value, the time it was observed and whether it is stale; a capability added to or removed from the registry appears or disappears everywhere with no consumer edit; a page served beside the write routes runs only script it shipped.

Current state

Implemented: routes, OpenAPI, MCP and the generated registry dataset are registry-derived and drift-checked. Partial: freshness, parity, Cockpit data access (five pages read ctx.registry directly, .ai/repo/ui-integrity-baseline.txt:9-13). Second registries: the clap tree (checked both ways by apps/majordomus-cli/src/capability/closure.rs), cli/local.rs LOCAL (89 commands), native web surfaces (apps/majordomus-cli/src/web/discover.rs:150), Cockpit routes (three lists, cross-checked), and the consumer copies listed in plan/RUNTIME_BASELINE.md.

Desired state

Every state-reporting answer carries observed_at and source, enforced over the registry; the parity property covers writers and the CLI; no Cockpit or site file names a value an enum, a capability or HttpExposure already declares; /swagger and every GET refuse what a hostile page or rebinding host could do.

Scope

  • apps/majordomus-cli/src/capability/builtin
  • apps/majordomus-cli/src/cockpit
  • apps/majordomus-cli/src/http
  • apps/majordomus-cli/src/live.rs
  • apps/majordomus-cli/src/index.rs
  • apps/majordomus-cli/src/site.rs
  • apps/majordomus-cli/src/web/discover.rs
  • share/cockpit
  • site/templates
  • apps/majordomus-cli/tests/properties.rs
  • apps/majordomus-cli/tests/dashboard.rs
  • test/cases
  • docs/SURFACES.md
  • docs/COCKPIT.md
  • .ai/repo/adrs/0004-canonical-architecture-and-performance-truth.md

Out of scope

  • Removing the clap tree or cli/local.rs LOCAL; both are measured second declarations (SURFACES F-1, F-4) and this milestone records them rather than rewriting the CLI.
  • Writing a static site that claims live state; the site stays a picture labelled as one.
  • Reporting a replaced executable, which is I1502.

Acceptance criteria

  • A test over the registry fails when a state-reporting capability answers without observed_at
  • The parity test covers every capability with an HTTP route and every capability with a CLI path
  • GET /swagger answers with a CSP and integrity hashes, and a foreign Host is refused on GET
  • A gate fails on a literal /api/v1/ path or a copied enum value in Cockpit or site code

Validation

  • bin/majordomus plan validate
  • cargo test --test properties --test projections --test dashboard --test http_serve --test http_host
  • bin/majordomus-cli generate --check
  • MJ_TEST_JOBS=4 bash test/run.sh 545_every_answer_says_when_it_was_observed 406_one_declaration_every_surface

Evidence required

  • uniform_freshness
  • parity_with_writers_and_cli
  • no_consumer_catalogue

Risks

  • Adding observed_at to capability outputs changes their schemas and so the public surface; version-surface will price it as a change, which is correct.
  • Extending parity to POST routes runs writers in tests; each must run against a synthetic repository, never the checkout.

Issues

Each one is an execution contract with its own acceptance criteria, validation command and required evidence. The wave column is the layer of the dependency graph it sits in.

issuestatuswavedepends ontitle
I2151 DONE 0 — A page served beside the write routes runs only script it shipped, and a rebinding host reads nothing
I2653 DONE 0 — Every diagram on the site is one interactive, linkable viewer whose node links are inferred, and a derived table can be drawn as a chart
I2654 READY 1 I2653 A chart is held to its table by a gate, and the tables that are measured series are drawn
I2655 READY 1 I2653 The homepage decides whether it carries a derived figure, within its declared story and budget
I2656 READY 1 I2653 The diagram viewer serves the Cockpit and majordomus ui, and a node that is a repository file links to its source
I2770 DONE 0 — majordomus ui and the Cockpit wear the site's navbar: one renderer, the same styles and scripts, and a browser comparison that refuses a difference
I2842 READY 0 — The live site is verified on a schedule, and its last verification is evidence
I2943 DONE 0 — A mesh this process is not on is said as not observed, never as zero or no
I3007 DONE 0 — A commit that a record or the site's data names is a commit the history holds
I3008 DONE 0 — A homepage link with a fragment resolves to an element its page carries
I3009 READY 0 — No record's prose and no board announcement holds a template delimiter
I3010 DONE 0 — The mesh manual says the edit guard is not wired, and how to wire it by hand
I3318 READY 0 — Every decision and curated note is read on /ui, with the records it names and the records that name it

The graph

surfaces-never-disagree dependency graphfrom .ai/repo/project
flowchart LR
    I2151["I2151<br/>A page served beside the write routes runs only script it shipped, and a rebinding host reads nothing"]:::done
    I2653["I2653<br/>Every diagram on the site is one interactive, linkable viewer whose node links are inferred, and a derived table can be drawn as a chart"]:::done
    I2654["I2654<br/>A chart is held to its table by a gate, and the tables that are measured series are drawn"]:::ready
    I2655["I2655<br/>The homepage decides whether it carries a derived figure, within its declared story and budget"]:::ready
    I2656["I2656<br/>The diagram viewer serves the Cockpit and majordomus ui, and a node that is a repository file links to its source"]:::ready
    I2770["I2770<br/>majordomus ui and the Cockpit wear the site's navbar: one renderer, the same styles and scripts, and a browser comparison that refuses a difference"]:::done
    I2842["I2842<br/>The live site is verified on a schedule, and its last verification is evidence"]:::ready
    I2943["I2943<br/>A mesh this process is not on is said as not observed, never as zero or no"]:::done
    I3007["I3007<br/>A commit that a record or the site's data names is a commit the history holds"]:::done
    I3008["I3008<br/>A homepage link with a fragment resolves to an element its page carries"]:::done
    I3009["I3009<br/>No record's prose and no board announcement holds a template delimiter"]:::ready
    I3010["I3010<br/>The mesh manual says the edit guard is not wired, and how to wire it by hand"]:::done
    I3318["I3318<br/>Every decision and curated note is read on /ui, with the records it names and the records that name it"]:::ready
    I2653 --> I2654
    I2653 --> I2655
    I2653 --> I2656
    classDef done stroke:#16a34a,fill:#dcfce7,color:#14532d,stroke-width:2px
    classDef active stroke:#2563eb,fill:#eff6ff,color:#1e3a8a,stroke-width:2px
    classDef verify stroke:#7c3aed,fill:#f5f3ff,color:#4c1d95,stroke-width:2px
    classDef ready stroke:#0891b2,fill:#ecfeff,color:#164e63,stroke-width:2px
    classDef planned stroke:#0891b2,fill:#ecfeff,color:#164e63,stroke-width:2px
    classDef blocked stroke:#b45309,fill:#fffbeb,color:#78350f,stroke-width:2px
    classDef cancelled stroke:#6b7280,fill:#f9fafb,color:#374151,stroke-width:2px
    classDef superseded stroke:#6b7280,fill:#f9fafb,color:#374151,stroke-width:2px

Canonical record: .ai/repo/project/milestones/surfaces-never-disagree.yaml. Read it back with majordomus plan show surfaces-never-disagree.

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