The surface where an operator sees the estate as relations: machines, the people who live on them, the things those people run, the scarce slots those things claim — and the ceremony that decided any of it could be there.
Version: 0.1.0 (stub)
Package: @medicine-wheel/app (routes) + @medicine-wheel/ui-components (components)
Document ID: rispec-infrastructure-topology-ui-v1
Status: Stub — the data layer ships, the surface does not
Last Updated: 2026-08-05
An operator opens one page and sees the estate whole — not as a list of servers, but as a web of relations they can walk in any direction they think in:
They can move between those readings without losing their place, and every reading answers from the same registered facts rather than from six separate dashboards that disagree.
What this enables: An operator asks the estate a question in the shape they are already thinking in, and gets an answer that carries its own accountability — who claimed this, who authorized it, who knows the thing about it that is not written down.
Structural Tension: The registered facts now exist and are reachable by agents through MCP
(list_infra_topology, detect_port_conflicts, reconcile_infra_state, hold_metis,
mw_enforce_gate). A human still has no surface. The tension resolves when the same six
perspectives an agent can request become six readings a person can see and move between.
What must not be flattened: A conventional infrastructure console renders machines as
inventory. This one renders them as relations — and it must show what inventory cannot hold:
that a port claim is a South precondition, that a running service is West, that a host is the
ground rather than a quadrant, that a heldBy name is a person and not a field.
The landing reading. What exists, arranged as the wheel arranges beings.
TopologyInspector beside the reading rather than
replacing it. Losing the shape of the estate to look at one part of it is how an operator stops
seeing the estate.PerspectiveSwitch, a WheelTopology, a ConflictBanner when any slot
is contested, and a TopologyInspector when a node is selected.One machine, and everything standing on it.
linger state rendered as a machine fact — never as a
permission, never with a check-mark. A tenant whose linger is unknown reads as unknown, not as
disabled: nobody has looked, and the surface must not decide for them.HostHeader, a stack of TenantCard, and a MetisPanel.The distance between what was written down and what is running.
undeclared
is first. Something running that nobody wrote down is the row that finds the service started
by hand at 2am — which is the service holding the port the next tenant is about to be given.DriftSummary, four DriftGroup sections, and an ObservationProvenance.Which agreements hold this infrastructure, and whether they still hold.
satisfied, unsatisfied, unauthorized, unknown. unauthorized must never
share a colour, an icon, or a section with unsatisfied: one is a machine that is not ready,
the other is a human who has not said yes or has withdrawn, and an operator who cannot tell them
apart will try to fix the second by restarting something.ConsentRecord that authorizes it — by id,
never as an embedded copy. A surface that copies a consent has made a withdrawable thing
permanent.PreconditionLadder, a ConsentTrail, and a MetisPanel.The control that changes what the estate is being asked.
The estate drawn as the wheel draws beings.
INFRA_ENTITY_BINDING. Hosts render at the centre, not in a quadrant — the land is what the
wheel stands on. Contested ports render as a shared edge between two claimants rather than as a
badge on one of them, because a collision belongs to both.part-of, binds-port,
ordered-after — and are individually dimmable, so an operator can read containment without
the port claims on top of it.tokens.css. Ceremony gold is reserved: it may mark a
ceremony-honored relation or a held métis, and it may never mark a control or a focus ring.A unix account rendered as a being.
linger. linger renders with
the words “machine fact” adjacent to it, permanently, not on hover. The moment that label is
something an operator has to go looking for, the surface has begun teaching them that the
checkbox is the permission.ServiceRow per owned service, and a MetisBadge when anything is held.The gate, rendered so its rungs stay distinguishable.
unauthorized reads as held, not as
broken.What people know that the schema cannot hold.
heldBy naming the
person, always visible, never collapsed into a count and never truncated to an avatar. Adding
to a hold appends and accumulates carriers; it never reassigns authorship of what someone else
wrote down.The whole registered estate under one perspective. Counts of hosts, tenants, services, port bindings, conflicts and held métis; the conflict rows; and the perspective-shaped body. Sourced from a single traversal so that every reading answers from the same facts.
An observation’s provenance — who read it, when, and how old it is — together with rows in four states and the port conflicts found over declared ∪ observed. Carries no memory of previous readings: it is recomputed from levels, every time.
A service, the preconditions gating it, each one’s verdict and the sentence that decided it, the count of preconditions declared, and every métis carried forward from a blocking gate.
Creative Advancement Scenario: The collision found before the tenant
User Intent: Give a second tenant a service on eury without taking something else down.
Current Reality: The operator knows eury is crowded and does not know which slots are free.
Natural Progression Steps:
eury.PerspectiveSwitch, WheelTopology port reading, ConflictBanner.Creative Advancement Scenario: The withdrawal that is not a failure
User Intent: Understand why a service will not come up. Current Reality: The gate is closed and the machine looks fine — linger is enabled, the unit is present, the working directory exists. Natural Progression Steps:
PreconditionLadder shows every machine half satisfied and one consent withdrawn.ConsentRecord and who can renegotiate it.
Achieved Outcome: The operator goes to a person instead of to a terminal.
Supporting Features: PreconditionLadder, ConsentTrail.Creative Advancement Scenario: The service nobody wrote down
User Intent: Trust the record enough to provision against it. Current Reality: The record was accurate the last time anyone checked, and nobody remembers when that was. Natural Progression Steps:
undeclared group sits first and holds one unit nobody declared.DriftSummary, ObservationProvenance, DriftGroup.Every reading above is already answerable. The surface composes existing calls; it invents no new data:
| Reading | Answered by |
|---|---|
| Topology, Host | list_infra_topology (perspective: host / tenant / service / port / metis) |
| Conflicts | detect_port_conflicts |
| Drift | reconcile_infra_state |
| Ceremony | mw_enforce_gate (precondition mode) |
| Métis | hold_metis, and the métis perspective |
| Direction routing | mw_get_direction (node_id) |
| Graph edges | get_relational_web (edge_types: ["part-of","binds-port","ordered-after"]) |
What this specification does not authorize. No screen here collects observed state. Reading a machine — systemd on gaia, runit on the device — is owned by the service-manager adapter lane (jgwill/medicine-wheel#118), and the drift screen takes its reading as input like everything else does. A surface that quietly grew a poller would put I/O inside a layer built to have none.
Current Reality: The facts are registered, validated, relationally edged and reachable by agents. A person has no surface. The existing app renders nodes, ceremonies, beats and graphs, and knows nothing of hosts, tenants, services or slots.
Desired State: Six readings of one estate, movable between without loss, each carrying its own provenance and its own accountability, and each refusing the four flattenings this system has already paid for: consent read as a checkbox, an unread fact read as false, a stale snapshot read as current, and a person’s knowledge read as a field.
Natural Progression: The perspectives already exist in the data layer as an enum. The surface resolves the tension by making that enum something a person can hold — the reading changes, the facts do not.
rispecs/graph-viz.spec.md — circular layout and directional quadrants this surface reusesrispecs/ceremony-protocol.spec.md — the gate whose verdicts the ceremony reading rendersrispecs/consent-lifecycle.spec.md — the record a precondition references and never copiesrispecs/ontology-core.spec.md — INFRA_ENTITY_BINDING, the closed NodeType union, and the
governed kinship edgessrc/infra/README.md — the facets, detectPortConflicts, preconditionGuard, reconcile🌸: The estate has been speaking in a language only agents could hear. This is the room where a person walks in and the machines finally introduce themselves — by name, with the people who know them standing alongside.