# mgf-hrb — Hardware Resource Broker
## Complete Architecture & Implementation Design

> A userspace layer on the kernel that brokers read/write access to all hardware for any client — reliable, fast, complete, and impossible to need to bypass. Designed as a kernel-agnostic contract so it lifts onto a from-scratch OS by writing one backend.

**Priorities, in strict order:** (1) Reliability · (2) Performance · (3) Fidelity · (4) Flexibility · (5) Simplicity.
**Languages:** Zig below the socket (enforcement, hardware, hot path) · Python above it (ergonomics, policy, tooling).
**Substrate:** Linux today (first backend) · a from-scratch capability-based kernel as the ultimate target.

This document is organized in nine parts. Parts 1–8 each design one slice and end with a SOLID report; Part 9 assembles them, scores the whole, and extracts a kernel-feature list for the future OS.

---

# Part 1 — Foundations & Governing Principles

This part sets the doctrine the rest of the design obeys. It is deliberately opinionated, because the value of principles is in the lines they let us *not* cross.

---

## 1.1 The priority order (every conflict resolves here)

When two desirable properties conflict, they resolve in this fixed order. This is the tie-breaker referenced throughout the document.

1. **Reliability** — correctness under failure. The system must never lie about ownership, never leak a claim, never corrupt hardware state. A slower-but-correct path beats a faster-but-fallible one.
2. **Performance** — blazing on the hot path. Subject only to (1), latency and throughput win over everything below.
3. **Fidelity** — complete and accurate representation of the hardware (see §1.4).
4. **Flexibility** — extensibility, clean seams, SOLID.
5. **Simplicity** — the smallest surface that satisfies the above.

> Note the deliberate ordering: flexibility and simplicity rank *below* reliability, performance, and fidelity. This is unusual and intentional. It means we will sometimes accept a more complex or less generic design to gain reliability or speed — and we will say so explicitly each time.

---

## 1.2 SOLID, applied where it earns its place

SOLID is a means, not an end. The priority order above outranks it. We apply each principle where it buys reliability, flexibility, or testability worth its cost — and we consciously decline it where it would tax the hot path or add ceremony without payoff. Every decline is recorded, not hidden.

### Single Responsibility (SRP) — "one reason to change"
Applied at the sibling-library granularity and again at the module granularity inside each. The test is *reason to change*, not size: mgf-hrb-cap changes when the security model changes; mgf-hrb-linux changes when the kernel ABI changes; these are different reasons, so they are different siblings.
- **High value:** keeps a kernel-ABI change from rippling into the security code, etc.
- **Declined where:** inside the hot path, we do *not* split a function just because it does two things, if splitting forces a call across a boundary that costs latency. Cohesion on the hot path can outrank SRP purity. (Recorded in Part 5.)

### Open/Closed (OCP) — "open to extension, closed to modification"
**The spine of the whole design.** Adding a bus (GPU), a backend (your future OS), a claim mode, or a resource kind must be *additive* — new code, not edited code. This is what makes the layer survive a decade and lift onto a new kernel.
- **High value:** everywhere. This is the principle we spend the most on.
- **Mechanism:** registries of implementations behind stable contracts (the backend registry, the worker registry, the resource-kind registry).

### Liskov Substitution (LSP) — "subtypes honor the contract"
**Most critical at the mgf-hrb-kabi seam.** Every kernel backend must be substitutable for every other *including its behavior under failure*, or the core's reliability guarantees break when ported. We therefore specify behavioral contracts (pre/postconditions, failure semantics), not just signatures.
- **High value:** the backend seam, the claim-mode implementations, the resource-kind behaviors.
- **Discipline:** a contract test suite that every backend must pass (Part 6). Substitutability is *verified*, not hoped.

### Interface Segregation (ISP) — "no client depends on what it doesn't use"
Maps onto the claim-mode lattice and the two resource families. An `Observe`-only reporter must not link, see, or depend on claim/release/revoke machinery. A Family-B reserver must not see Family-A claim verbs.
- **High value:** keeps the read-only majority of clients tiny and unable to even express a dangerous operation (security dividend).
- **Mechanism:** the 8-verb surface is decomposed into role-interfaces (Part 8); capabilities enforce at runtime what ISP expresses at the type level.

### Dependency Inversion (DIP) — "depend on abstractions"
**Already the deepest principle in the design.** The core depends on the *abstract* kernel interface (mgf-hrb-kabi), never on Linux. We extend the same inversion to transport, capability verification, and policy: the core never names a concrete mechanism.
- **High value:** the kernel seam (enables the OS port), the policy seam (enables policy changes without core changes).
- **Direction rule:** dependencies point toward `mgf-hrb-model` (pure vocabulary, depends on nothing) and toward abstractions; concretes (mgf-hrb-linux, the socket transport) are leaves nothing depends on.

---

## 1.3 The dependency direction law

One law governs all inter-sibling dependencies, and it is the mechanical form of DIP + OCP:

> **Dependencies point toward stability and abstraction. The pure vocabulary (`mgf-hrb-model`) depends on nothing. Abstractions (`mgf-hrb-kabi`, capability/transport traits) depend only on the vocabulary. Concrete implementations (`mgf-hrb-linux`, socket transport, per-bus workers) are leaves — depended upon by nothing in the core.**

Consequences:
- The core (`mgf-hrb-core`) can be compiled and unit-tested with *no* kernel, *no* socket, *no* hardware — every dependency is an abstraction with a fake.
- Porting to your OS adds a leaf (`mgf-hrb-youros`); nothing the leaf depends on changes.
- No Linux noun (`fd`, `ioctl`, `/sys`, `netlink`) may appear above `mgf-hrb-kabi`. This is mechanically enforceable (a symbol/lint check) and is the single most important portability rule.

---

## 1.4 The fidelity guarantee — "fully represent the hardware"

You asked for an interface that is *complete, accurate, reliable, and fast*, that *fully represents the hardware*, and that *nobody needs to bypass*. That is a real, testable design property, not a slogan. We define it precisely as four sub-guarantees:

### G1 — Completeness (no capability is unreachable)
For every operation the hardware physically supports, there exists a path *through* the broker to perform it — either modeled as a typed operation, or reachable via the **raw capability channel** (Part 3) on a resource you own. the broker need not *model* every register to *mediate* every access. Completeness is measured as: "can a legitimate owner reach any hardware capability through the layer?" — and the answer must always be yes.

### G2 — Accuracy (the model never lies)
A `Resource` descriptor reflects the *true current state* of the hardware, not a stale cache. State that can change underfoot (link status, ownership, presence) is either read live or invalidated by an event before it can be read stale. Where the kernel cannot provide a fact cheaply, the descriptor marks it `Unknown` rather than guessing. **An accurate "I don't know" outranks a fast wrong answer** (priority #1 over #2 over #3).

### G3 — Reliability of representation (truth survives failure)
Ownership and presence facts remain correct across client crashes, worker restarts, and facade restarts. A device whose owner died is shown `Free` after safe-reset — never stuck `Claimed` by a ghost. The lease engine (Part 3) is what enforces G3.

### G4 — Fidelity has no speed tax on use
Representation accuracy is maintained on the *control* path (enumerate/inspect/subscribe). It imposes **zero** overhead on the *use* path — once you hold a direct handle, the layer is not consulted, so fidelity bookkeeping never slows hardware access (priority #2 preserved).

> The four together are the precise meaning of "fully represent the hardware": everything is reachable (G1), what we say is true (G2), it stays true under failure (G3), and saying so costs nothing on the hot path (G4). Each is given an enforcement mechanism in its respective part, and a test in Part 9.

---

## 1.5 The "no need to bypass" theorem

A restatement that ties G1–G4 to the priority order, because it is the design's central claim:

> A client bypasses an abstraction for exactly two reasons: it is *missing a capability* (incompleteness) or it is *too slow* (overhead). G1 removes the first reason — everything is reachable through a claim, including raw access. G4 removes the second — owned access is direct, as fast as raw. With neither reason present, bypassing is both unnecessary and pointless. Therefore a correct client never bypasses, and an incorrect one gains nothing by trying. The layer is the single point of truth *by construction*, not by policy or enforcement alone.

This theorem is the reason the priority order puts reliability and performance above flexibility: the bypass-proofness depends on *both* completeness (a fidelity/flexibility property) *and* zero-overhead use (a performance property). Sacrifice either and clients route around the layer, and ownership truth — the whole point — decays.

---

## 1.6 The survivability guarantees — "never a place to attack or fault"

G1–G4 (1.4) guarantee the layer tells the *truth about hardware*. They do **not**, by themselves, guarantee the layer *survives a hostile or broken world*. Because mgf-hrb is intended as the standard way userspace touches hardware — used heavily, by many mutually-competing tenants, on real hardware that can fail or misbehave — survivability is a first-class requirement, not an emergent hope. We name it as five guarantees (S1–S5), peers of G1–G4, each with its own adversarial conformance suite (Part 6).

### The threat model (the frame these guarantees defend)
The broker is a **membrane between two untrusted worlds**, with mutually-untrusted tenants on the upper side:
- **Clients/tenants (the upward boundary)** are *untrusted*: any request, byte in shared memory, fd, or capability token is hostile until validated. Tenants are *mutually* untrusted — competing concurrently for the same hardware.
- **Hardware/devices (the downward boundary)** are *untrusted*: a device may be dead, frozen, slow, or malicious (rogue DMA, lying firmware). Failure here is often not an error return but the *absence* of one — a call that never comes back.
- **The kernel/driver** is *semi-trusted*: **unreliable but not malicious** — it may be buggy, slow, or block indefinitely, and we defend against that, but we do not defend against a hostile kernel (that is the kernel's own threat model).
- **The hardware can be malicious only within what the IOMMU contains** — rogue DMA is contained by an IOMMU that must be *verified present and active*, not assumed. A no-IOMMU host is a declared degraded mode with DMA-capable passthrough disabled.
- **The privileged helper's small TCB is assumed correct** — which is precisely why it is minimized (Part 11). The large policy layer and every client are *not* assumed correct.
- **Microarchitectural side channels** (Spectre-class, power, EM) are out of scope except where the broker's own design would widen them (e.g. shared memory across tenants — addressed by per-tenant private regions, Part 5/7).

### S1 — Upward crash-safety
No sequence of client actions — malformed or wrongly-typed requests, oversized input, poisoned shared memory, capability-forgery attempts, request floods, slowloris — may crash, hang, or corrupt the broker. **The worst a client can do to the broker is lose its own connection.** Enforced by a single hardened *trust gate*: all client bytes pass through typed validation before becoming a request; nothing past the gate ever touches raw client input.

### S2 — Downward fault-containment
No device or kernel behavior — timeout, freeze, privilege error, spurious interrupt, hotplug-during-operation, success-then-lie — may crash or indefinitely block the broker. **Every downward operation is bounded in time and total in error handling.** Enforced by *deadlines* as part of the seam contract (Part 6): every backend operation completes, errors, or is abandonable within its deadline; a frozen device costs at most one bus worker, which the supervisor respawns. A timed-out or unverifiable operation moves the resource to `Quarantined` (Part 2), never to a false `Free` or an ambiguous state.

### S3 — Tenant isolation
No tenant may read, corrupt, observe beyond policy, or deny service to another tenant's resources or data, except through explicitly modeled, policy-permitted sharing. Enforced by: capability-scoped namespaces (a tenant cannot even *enumerate* resources outside its grant), per-tenant private shared-memory regions (no cross-tenant ring, zeroed before reuse — no residual data, no timing side channel), and fairness policy (Part 5) so no tenant can starve another.

### S4 — Self-fault containment
A bug, panic, or resource exhaustion in any broker component is contained to the smallest blast radius — at most one bus worker — recovers automatically, and never escalates to total failure or to a reliability lie (a ghosted lease, a corrupted ownership table). Enforced by the per-bus-worker process model (Part 7) and a *re-derive-don't-persist* recovery contract: a restarted component reconstructs truth from authoritative sources (the hardware/IOMMU + live client connections), never from lost in-memory state; anything uncertain is quarantined.

### S5 — Bounded everything
Every resource the broker consumes on behalf of clients — memory, fds, table entries, CPU time, lease count, connections — is bounded per-tenant and in aggregate, so no actor can exhaust the broker or the host. Enforced by back-pressure: when a bound is hit, the broker returns a typed `Overloaded` error rather than growing unboundedly. OOM is impossible by construction, not handled after the fact.

### The survivability/performance relationship (why these are free)
Every S-guarantee's enforcement lands on the **cold control path** (claim, release, revoke, enumerate, restart, validate). The **hot path is the use path** — direct hardware access via an owned handle, with the broker absent (G4). No S-guarantee touches it. Deadlines are free when not hit; quarantine is a state, not a per-access check; revocation is rare; the trust gate runs once per request, never per hardware access. **The same control/use split that makes the broker fast (G4) is what makes it cheap to harden.** Survivability and peak performance are both consequences of that split, not trade-offs against each other.

### The revocation principle (reconciling G4 with S1/S3)
G4 (delegate usage, broker steps out) means a client *keeps a working handle* after a grant. For revocation (a dead, preempted, or policy-violating client must lose access *now*), the broker therefore revokes **below the delegated handle**, not in front of it: it tears down the IOMMU/DMA mapping the handle depends on, rendering the client's fd inert (accesses fault) without the broker being in the use path. *The handle is a straw; revocation pulls what it drinks from.* This single principle reconciles the performance model with instant revocation, and is the mechanism behind preemption for multi-tenant fairness (Part 5). On a capability-native kernel it becomes native handle revocation — another feature `mgf-hrb-youros` makes easy that Linux makes hard.

---

## 1.7 What this part commits us to

- A written priority order that resolves every later conflict (1.1).
- SOLID applied with named exceptions, never dogmatically (1.2).
- A single mechanical dependency law, lint-enforceable (1.3).
- A four-part fidelity guarantee with enforcement and tests (1.4).
- A theorem that makes "nobody bypasses" a structural property, not a hope (1.5).
- A stated threat model and five survivability guarantees (S1–S5) with adversarial conformance tests, making "never a place to attack or fault" a verified property rather than an intention (1.6).

The remaining parts each implement a slice of this and, at their end, report which SOLID principles they honored and which they consciously declined — feeding the scorecard in Part 9.
# Part 2 — The Resource Model & Fidelity (`mgf-hrb-model`)

`mgf-hrb-model` is the pure vocabulary every other sibling speaks. Per the dependency law (Part 1.3) it depends on **nothing** — no kernel, no transport, no I/O. It is data types and the rules over them. This is what lets the core compile and test with no hardware, and what lifts unchanged onto your future OS.

**Language:** the canonical types are defined in **Zig** (the wire/ABI truth), with generated **Python** mirrors for `mgf-hrb-sdk-py`. The Zig definition is authoritative; Python is a projection of it (Part 8 covers generation).

---

## 2.1 The two families — formalized, and why they must not merge

Part 1 asserted two resource families. Here is the formal distinction, because it is the model's backbone and the most consequential SRP boundary in the system.

| | **Family A — Claimable** | **Family B — Apportionable** |
|---|---|---|
| Nature | discrete, indivisible thing | continuous, divisible quantity |
| Examples | PCIe function, USB interface, GPU, block dev, NIC | CPU shares, memory/hugepages, NUMA, thermal budget |
| Ownership | *held* — one owner (or a shared set) at a time | *apportioned* — many holders of fractions |
| Core verb | `claim` / `release` | `reserve` / `release` |
| Conflict | exclusivity collision (two want the same thing) | over-subscription (sum of fractions > capacity) |
| Failure on death | safe-reset the device | return the fraction to the pool |
| Identity | the device *is* the resource | the resource is a *budget against* a pool |

> **Why not one unified "Resource" with a flag?** Because they differ in their *reason to change* (SRP) and their *invariants*. A claimable resource's invariant is "at most one exclusive owner"; an apportionable resource's invariant is "sum of reservations ≤ capacity." Merging them forces every consumer to handle both invariant families and every code path to branch on the flag — the model would leak its internal split into every caller. Two types with a shared *namespace* (below) is cohesive; one type with a mode flag is coupling wearing a trenchcoat.

The two families share a **namespace and discovery mechanism** (§2.3) but **not a contract**. This is ISP at the model layer: a Family-A consumer never sees `reserve`, a Family-B consumer never sees `claim`.

> **Mode vocabularies are per-family.** Family A's mode space is the **claim-mode lattice** (§3.3 — `Observe` / `Shared(rw)` / `Exclusive`, with `Steal(p)` as a request strategy). Family B has no mode lattice; it has a **reservation-strength axis** (`Guaranteed` / `BestEffort` / `Burstable`), settled in Part 10 (`mgf-hrb-family-b-deepening.md` §2). The lattice doesn't generalize and the axis doesn't either — they are the disjoint contracts the two families' ISP split makes visible. Earlier text that read the lattice as universal was Family-A-coloured by accident; treat the lattice as Family-A specific from here on.

---

## 2.2 The universal descriptor

Every resource — either family — is a node carrying identity, structure, typed facts, live state, and a capability gate.

```zig
const Resource = struct {
    urn:       Urn,              // stable identity, §2.4
    family:    Family,           // Claimable | Apportionable
    kind:      Kind,             // pcie_function | usb_interface | cpu_set | ... (open set, §2.5)
    parent:    ?Urn,             // topological parent (bus/controller/NUMA node)
    children:  []const Urn,      // topological children
    attrs:     AttrMap,          // typed, kind-specific facts (§2.6)
    state:     State,            // live ownership/availability (§2.7)
    caps_req:  CapSpec,          // proof needed to observe / control / claim (Part 4)
    fidelity:  FidelityTag,      // how trustworthy each field is right now (§2.8)
};
```

Three design notes that matter:

- **`kind` is an open set, not an enum** (§2.5). New hardware kinds are added without modifying the model — OCP at the type level.
- **`attrs` is typed, not stringly.** Each kind declares a typed schema for its attributes (a PCIe function has `vendor_id: u16`, `bar: [6]BarDesc`, `link_speed: LinkSpeed`). Stringly-typed attribute bags are how fidelity rots; we forbid them.
- **`fidelity` travels with the descriptor** (§2.8). Accuracy (G2) is not a global promise; it is a *per-field* tag the caller can inspect.

---

## 2.3 The namespace — one navigable tree for the whole machine

The entire machine is a single tree addressed by URN. This is the unifying creative move: one model, every consumer.

```
hw:/
├─ pci/
│  └─ 0000:01:00.0/
│     ├─ fn0          (Claimable: pcie_function)
│     └─ fn1          (Claimable: pcie_function)
├─ usb/
│  └─ bus1/
│     └─ dev4/
│        └─ if0       (Claimable: usb_interface)
├─ cpu/
│  ├─ topology        (Apportionable: cpu_set)
│  └─ numa0           (Apportionable: memory_region)
└─ thermal/
   └─ zone0           (Apportionable: thermal_budget)
```

- **Glob addressing**: `hw:/pci/**` selects a subtree; `hw:/**/if0` is invalid (no wildcards in the middle that cross kinds — keeps queries cheap and predictable). Globs drive `list` and `subscribe`.
- **The tree is topological, not functional** — it mirrors how hardware physically connects (controller → bus → device → function), because that is the structure that is *true* regardless of use. Functional groupings (IOMMU groups, NUMA affinity) are *attributes/relations* (§2.6), not the tree, because they are views over the same nodes.

> This addresses your "fully represent the hardware" intent in its *structural* sense: the tree is a faithful topological twin of the machine. A bus-layout reporter renders the tree directly; it *is* the hardware's shape.

---

## 2.4 URN stability (the identity problem) — feeds G2/G3

A resource's `urn` must be **stable across reboots and re-plugs** wherever physically possible, because policy and capabilities reference resources by identity. The model defines a stability ladder, and the descriptor records which rung a given URN sits on:

1. **Topological** (`hw:/pci/0000:01:00.0/fn0`) — stable as long as the device stays in the same slot. Cheap, default.
2. **Intrinsic** (serial number, WWN, MAC) — stable across slots; used when the kind exposes a hardware identity.
3. **Synthetic-pinned** — an admin-assigned stable alias mapped to an intrinsic id, for devices with no stable hardware identity.

The descriptor exposes `urn` (the addressing handle) and `identity_class` (which rung), so a caller knows whether "the same URN tomorrow" means "the same slot" or "the same physical device." **Honesty about identity stability is itself a fidelity guarantee** — we never imply more stability than the hardware provides.

### 2.4.1 Identity continuity across re-enumeration — the runtime comparator

The stability ladder is *static* — a fact recorded once per descriptor. There is a *runtime* sibling problem: a device drops off the bus and re-appears with a different `pid`, possibly a vanished `serial_number`, sometimes a different `if<K>` set (the canonical case is the iFig DFU sequence — Normal → Recovery → DFU with the serial dropping mid-transition). A consumer mid-flow needs to answer **"is the device I see now the same physical unit I started with?"** without relying on URN equality.

The model carries two affordances for this:

- **`Snapshot`** — a backend-free, immutable capture of a `Resource`'s identity (the URN, the `identity_class`, the per-rung evidence). Survives the device disappearing from the bus.
- **`same_likely(snapshot, candidate) -> Confidence`** — a comparator returning `SAME / LIKELY_SAME / AMBIGUOUS / DIFFERENT`, computed by per-dimension scoring across the rung evidence. The algorithm lives in the model; the *weights* are per-bus (the USB worker tolerates a vanished serial within a mode-change window; PCI does not, because PCI BDF is far more stable). Same mechanism/meaning split as core-vs-policy (§3.1): the *math* is mechanism, the *defaults* are per-bus meaning.

The detailed algorithm and weight table appear in [`mgf-hrb-usb-worker.md`](mgf-hrb-usb-worker.md) §4 — the worker where it most matters. Resolved by [FEEDBACK paper `MODEL-01`](../FEEDBACK.md).

> **Shipped (commit `14d3d5e`).** The comparator is in code on both
> sides of the socket: `hrb-code/src/identity.zig` (the canonical
> implementation; 18 pinning tests in `identity_test.zig`) and
> `src/mgf/hrb/identity.py` (the Python mirror; drift detection per
> D-035 lives in `tests/unit/mgf/hrb/test_identity.py`, which scores
> the same iFig fixtures against the same expected verdicts).
> Exposed from the SDK as `from mgf.hrb import Snapshot, same_likely,
> same_likely_explained, Confidence, ComparatorOpts`. See
> `examples/03_track_identity.py` for the minimal consumer pattern
> and `recipes/track-a-device-across-a-mode-change.md` for the
> integration story.

> **Gotcha worth recording.** Some buses carry an *ephemeral* per-session id alongside the topological URN (USB's kernel devnum, which rotates on every replug, is the canonical case). It does **not** belong in the URN — but it *is* a useful attribute (some ioctls take it). The descriptor exposes it as an attribute with fidelity `live` and an explicit "ephemeral" tag so no consumer stores it as identity by mistake.

---

## 2.5 Open `kind` set — OCP for hardware types

`Kind` is an extensible registry, not a closed enum:

```zig
const KindDescriptor = struct {
    name:        []const u8,        // "pcie_function"
    family:      Family,
    attr_schema: AttrSchema,        // the typed shape of attrs for this kind
    ops:         OpsTable,          // which typed operations this kind supports (§2.6)
    reset_fn:    *const fn(...) Err!void,  // how to safe-reset (Family A) — feeds G3
};
```

Adding GPU support = registering a `KindDescriptor`. The model, the core, the facade — none change. This is the OCP spine made concrete at the type layer: **the set of representable hardware is open; the code that manipulates it is closed.**

---

## 2.6 Typed operations + the raw channel — the G1 (completeness) mechanism

Each kind declares an `OpsTable` of *typed* operations it supports (a PCIe function: `read_config`, `write_config`, `map_bar`, `reset`; a USB interface: `claim_interface`, `bulk_transfer`, `reset`). These are the *modeled* capabilities — ergonomic, type-checked, the 90% path.

For the unmodeled 10% — the obscure register poke, the vendor-specific command no schema covers — the kind also exposes a **raw capability**: a typed request for a *direct channel* to the underlying resource (Part 3 grants it; the kernel backend, Part 6, materializes it). The model's job is only to *declare that a raw channel is obtainable* for a kind and *what shape* the channel takes (a memory-mappable region, a byte-stream fd, a config space).

> This is the model-layer half of G1/the no-bypass theorem: the model guarantees that for every kind, **either** the operation is typed **or** a raw channel reaches it. There is no third category "unreachable." A kind that could have an unreachable capability fails review.

OCP note: typed ops are the extension surface — adding a typed op to a kind is additive; the raw channel is the safety net that makes the system complete *even before* an op is modeled. You ship with few typed ops and the raw channel covering the rest, then promote hot/common raw uses into typed ops over time without ever having been incomplete.

---

## 2.7 State — the live truth (G2/G3 mechanism)

```zig
const State = union(enum) {
    free,
    claimed:     struct { owner: ClientId, mode: ClaimMode, lease: LeaseId },
    shared:      struct { owners: []const ClientId, mode: ClaimMode },
    reserved:    struct { fraction: Ratio, holders: []const Reservation },  // Family B
    absent,                              // was present, now unplugged — not yet pruned
    faulted:     struct { reason: FaultCode },           // hardware error state
    quarantined: struct { reason: QuarantineReason, since: Timestamp },  // see below
};
```

`State` is **never cached as fact** — it is owned by the core's lease engine (Part 3) and reflects the live ownership table. A reader of a descriptor gets the state as of the read, and may `subscribe` (§2.9) to be told when it changes. The `claimed.lease` link is what makes G3 enforceable: when a lease dies, the engine knows exactly which state entry to revert.

### 2.7.1 `quarantined` — the safe home for anything uncertain (Part 12 §2.4)

`Quarantined` is a first-class state introduced by the survivability review (Part 12): the safe home for a resource we cannot be sure is in a known-good condition. A device transitions into `quarantined` when any of the following happens:

- A backend op (`acquire` / `reset` / `map_region`) **times out** — the deadline ran out before the kernel/device returned (D-029 / Part 12 §2.2). Returning the device to `free` would risk leaking prior-tenant state; reporting it `faulted` would be too strong (the device may yet recover).
- A **`reset` succeeded at the kernel layer but failed post-condition verification** — the kernel reported success, the read-back didn't confirm safe state. The device is "honestly fooled" (Part 12 §2.3).
- A worker restart found a device the **backend reports as still-acquired but no surviving client claims** — a ghost from a tenant that died during the restart window (§3.7 reconciliation).
- A tenant's authority was **revoked mid-flow**, the IOMMU mapping has been torn down (§3.5 `revoke()` below the fd), but the device hasn't yet been verified clean for the next claimant.

Quarantine's contract:

- **Never granted to any client** — a `claim` against a `quarantined` URN returns `Err.Unavailable` with the reason, the next-step `Fix`, and the `since` timestamp.
- **Reported truthfully** — `inspect`/`list` surface the state and reason, so operator tools (`mgf-hrb doctor`) can render it.
- **Recovered only via verified clean reset** — the recovery path runs a stronger reset level (or operator-driven manual reset) and verifies the post-condition before promoting back to `free`. Verification path lives in the privileged helper.
- **Subject to a recovery policy** — escalating reset / cool-down / operator alert; meaning lives in `mgf-hrb-policy`.

`Quarantined` is the downward-boundary analog of how the lease engine handles the upward boundary: ghosts are impossible because every state is accounted for, including "we don't currently trust this device."

---

## 2.8 The fidelity tag — making G2 inspectable, not just promised

Every descriptor carries a per-field trustworthiness tag. This is the mechanism that lets the system say an honest "I don't know" instead of a confident wrong answer (Part 1.4, G2):

```zig
const FieldFidelity = enum {
    live,       // read directly from hardware just now — fully trustworthy
    cached,     // from a recent read; valid until the next invalidating event
    inferred,   // derived, not directly observed (e.g. capacity from a spec table)
    unknown,    // the backend cannot determine this — explicitly not guessed
};
```

- A field marked `unknown` is the system refusing to lie. Callers handle it explicitly; they cannot mistake a guess for a fact.
- `cached` fields are bound to an invalidation event: if the fact can change, an event (§2.9) *must* fire before the cache can be read stale, or the field may not be marked `cached`. This is the contract that makes "accurate" testable (Part 9 fuzzes it).
- This tag is *free on the use path* (G4): it is metadata on the control-path descriptor only; it never touches a granted direct handle.

> Most systems present hardware facts with uniform false confidence. The fidelity tag is a small, novel honesty mechanism: the model carries *how much it knows* alongside *what it knows*.

---

## 2.9 The event model — keeping representation true over time

Hardware is dynamic. A one-shot enumeration is stale the instant it returns. The model defines a typed event stream so every consumer can keep its view true:

```zig
const Event = union(enum) {
    added:             struct { urn: Urn, snapshot: Resource },
    removed:           struct { urn: Urn },
    state_changed:     struct { urn: Urn, old: State, new: State },
    ownership_changed: struct { urn: Urn, old: ?ClientId, new: ?ClientId },
    attr_changed:      struct { urn: Urn, key: AttrKey, fidelity: FieldFidelity },
    faulted:           struct { urn: Urn, reason: FaultCode },
};
```

- This *replaces* the scattered Linux mechanisms (udev, netlink, sysfs polling) with one uniform typed stream — a fidelity and simplicity win simultaneously.
- Events are the invalidation mechanism behind `cached` (§2.8) and the notification behind `subscribe` (Part 8). Delivery is over the shm ring (Part 5), so high-rate event storms (USB hotplug floods) cost no syscalls per event (G4-adjacent: keeps the control path fast too).
- **Ordering guarantee:** events for a single URN are totally ordered; events across URNs are not globally ordered (only causally, via the parent link). This is the weakest guarantee that still lets a consumer maintain a correct per-resource view — deliberately not stronger, because global ordering would force a serialization bottleneck (priority #2).

---

## 2.10 SOLID report for Part 2

- **SRP — honored, strongly.** The two-family split is the central SRP decision; `mgf-hrb-model` holds vocabulary only, no behavior, no I/O.
- **OCP — honored, strongly.** Open `kind` set (§2.5) and typed-ops registry (§2.6) make new hardware additive. This is the model's biggest contribution to the OCP spine.
- **ISP — honored.** Families A/B expose disjoint verb sets; consumers see only their family's contract.
- **DIP — honored by construction.** The model depends on nothing; everything depends on it. It is the stable root of the dependency law.
- **LSP — deferred to Part 6** (it governs *implementations* of kinds/backends, which live below the model). The model defines the contracts LSP will be tested against.
- **Consciously declined:** none in this part — the model is pure data, where SOLID is cheap and wholly worth it. The only restraint exercised was *not* over-modeling: typed ops cover the common path, the raw channel covers the rest, so we resist the temptation to model every register up front (which would violate the priority order's #5 simplicity for no fidelity gain, since the raw channel already guarantees completeness).

---

## 2.11 What Part 2 commits us to

- A two-family model with disjoint contracts but a shared topological namespace (2.1–2.3).
- An honest identity story with a stability ladder (2.4).
- An open, typed `kind` registry — OCP for hardware types (2.5).
- Completeness by construction: typed ops *or* a raw channel, never unreachable (2.6) — the model half of G1.
- Live state owned by the core, never cached as fact (2.7).
- A per-field fidelity tag that lets the system say an honest "unknown" (2.8) — the mechanism for G2.
- A uniform typed event stream that keeps every view true over time (2.9).

Part 3 takes this vocabulary and builds the arbiter on top: the lease engine that owns `State`, enforces the claim lattice, and makes G3 (truth-survives-failure) real.
# Part 3 — The Arbitration Core (`mgf-hrb-core`)

This is the hard heart — the part that makes the broker a broker rather than a passthrough. It owns the one fact nothing else may own: **who holds what, right now, truthfully, even across failure.** Everything else in the system is in service of keeping that fact correct and cheap to consult.

**Language:** Zig, entirely. This is below the socket — privileged-adjacent, on the contention path, holds the ownership table that must never be corrupted by a GC pause or an unwinding exception. Reliability (priority #1) lives here, so the language with deterministic memory and explicit error handling owns it.

**Dependencies (per the law, Part 1.3):** depends on `mgf-hrb-model` (vocabulary) and on the *abstract* `mgf-hrb-kabi` (kernel operations) and *abstract* capability verification (`mgf-hrb-cap`). It depends on **no concrete backend, no transport, no hardware** — so it compiles and unit-tests against fakes with zero devices present.

---

## 3.1 What the core is responsible for (and what it refuses)

SRP, drawn sharply, because the core is where scope-creep would be fatal:

**The core owns:**
- The **ownership table** — the single source of truth for every resource's `State` (Part 2.7).
- The **lease lifecycle** — grant, renew, expire, revoke, and the safe-reset that follows loss.
- The **claim-mode lattice** — deciding whether a requested claim is compatible with current holders.
- **Revocation arbitration** — cooperative preemption between competing claimants.

**The core explicitly refuses (delegates elsewhere):**
- *Touching hardware* → delegated to `mgf-hrb-kabi` backends (Part 6). The core decides *who may*; the backend performs.
- *Verifying capabilities* → delegated to `mgf-hrb-cap` (Part 4). The core *asks* "is this permitted?"; it does not implement the answer.
- *Transport/serialization* → delegated to `mgf-hrb-rt` (Part 5). The core speaks in types, not bytes.
- *Policy* (priorities, who-beats-whom) → delegated to `mgf-hrb-policy` (Python, Part 8). The core *enforces* a decision; it does not *choose* the decision.

> The last refusal is the most important and the cleanest DIP/SRP win in the system: **the core is mechanism; policy is meaning.** The core knows *how* to revoke a lease; it asks policy *whether* to. This means the contested, opinion-laden, frequently-changing part (policy) lives in Python where it is easy to change, while the must-never-break part (the mechanism) lives in Zig where it is hard to break. The two have different reasons to change and different reliability requirements — so they are different siblings in different languages, split exactly along the mechanism/meaning line.

---

## 3.2 The lease — the atom of ownership

Every grant of access is a **lease**, never a bare lock. This is the single most important reliability decision in the whole system; G3 (truth survives failure) rests entirely on it.

```zig
const Lease = struct {
    id:         LeaseId,           // unique, monotonic, never reused
    resource:   Urn,
    holder:     ClientId,          // bound to a live connection (§3.6)
    mode:       ClaimMode,         // §3.3
    priority:   Priority,          // from policy; used in revocation (§3.5)
    granted_at: Timestamp,
    expires_at: ?Timestamp,        // null = bounded only by liveness, not wall-clock
    revocable:  RevocabilityContract,  // §3.5 — can the holder be asked to yield?
};
```

The defining property: **a lease exists only while its holder is provably alive.** It is not a permission you are handed and keep; it is a continuously-renewed truth. The instant liveness fails (connection drop or missed heartbeat, Part 5), the lease is *gone* and the engine reclaims the resource. There is no path by which a dead client keeps ownership — so there is no leaked-claim state to ever observe (G3).

> Locks leak on crash; leases cannot. Choosing "lease, always" over "lock, sometimes" is choosing a system that *cannot* enter the stuck-owned-by-a-ghost state, rather than one that tries to clean it up after the fact. This is reliability by construction (priority #1), and it is why the recovery-tool-crashes-mid-flash case self-heals with no special handling.

---

## 3.3 The claim-mode lattice — compatibility as a partial order  *(Family A only)*

> **Family scope.** This lattice governs *Family A — Claimable* resources (PCIe function, USB interface, GPU, block dev, NIC). Family B — Apportionable resources (CPU shares, memory) have no lattice; they have a **reservation-strength axis** (`Guaranteed` / `BestEffort` / `Burstable`) defined in Part 10. The two families share a namespace but not a mode vocabulary (§2.1).

A claim requests a *mode*. The engine grants it only if the mode is compatible with all current holders. The modes form a lattice with an explicit compatibility relation:

| Requested ↓ vs Held → | (none) | Observe | Shared(rw) | Exclusive |
|---|---|---|---|---|
| **Observe** | ✓ | ✓ | ✓ | ✓ (read-only never conflicts) |
| **Shared(rw)** | ✓ | ✓ | ✓ (cooperative) | ✗ |
| **Exclusive** | ✓ | ✗ | ✗ | ✗ |
| **Steal(p)** | ✓ | ✓ | revoke if p>held | revoke if p>held (§3.5) |

Key properties:
- **`Observe` is always compatible with everything**, including `Exclusive`. Reading topology/state never conflicts with controlling a device. This is why the read-only majority of clients (reporters, mappers) never contend — they cost nothing and block nothing. (ISP dividend: most clients only ever request `Observe` and never even touch the contention machinery.)
- **`Exclusive` is compatible only with nothing-or-Observers.** A flasher gets exclusive control while a monitor still watches state.
- **`Shared(rw)`** is for genuinely cooperative co-owners (two subsystems that have agreed on a protocol). The engine permits it; the *coordination* is the holders' problem, not the broker's.
- **`Steal(priority)`** is not a fifth mode of *holding* — it is a *request strategy* that triggers revocation (§3.5) against lower-priority holders. It is how the GPU gets pulled from host use into a VM.

The compatibility check is **O(1)** against the resource's current holder set (small, usually 0–1 entries). The contention path is fast (priority #2) even though it is the "slow" control path relative to use.

---

## 3.4 The grant sequence — atomicity and partial-failure safety

Granting a claim touches three subsystems (capability check, backend acquire, table update). It must be **atomic**: either the lease exists *and* the hardware is acquired *and* the table reflects it, or none of those. Partial state here is the corruption we cannot allow.

```
claim(urn, mode, client) →
  1. cap check        [mgf-hrb-cap]   — permitted? (no hardware touched yet)
  2. compatibility    [core]          — mode compatible with holders? (§3.3)
  3. reserve slot     [core]          — tentatively record intent (not yet committed)
  4. backend acquire  [mgf-hrb-kabi]  — actually claim the hardware (VFIO bind, etc.)
  5. commit lease     [core]          — table now authoritative; lease live
     ── on ANY failure in 1-4: errdefer unwinds, slot released, NOTHING committed ──
```

Zig's `errdefer` is load-bearing here: each step registers its undo, and any failure unwinds the partially-acquired state deterministically — no GC, no exception unwinding through half-bound hardware. **Step 4 is the only one that touches hardware, and it is last among the fallible steps**, so a rejected claim never leaves a device half-acquired. If step 4 itself partially fails, its own `errdefer` (in the backend) safe-resets before returning. This is reliability priority #1 expressed as control flow.

> Why not commit the lease *before* acquiring hardware (optimistic)? Because then a backend-acquire failure would leave the table claiming ownership of a device the broker doesn't actually hold — a G2/G3 violation (the model would lie). We pay a tiny latency cost (acquire before commit) to never lie. Priority order: reliability > performance, explicitly applied.

---

## 3.5 Revocation — cooperative preemption without corruption

When a high-priority claimant wants a resource a lower-priority holder has, the engine runs cooperative preemption. This is the politics of contention, and it must be both *fair* (per policy) and *safe* (never corrupting).

```
revoke(target_lease, reason) →
  1. policy decides    [mgf-hrb-policy]  — does the requester actually outrank the holder?
  2. if holder.revocable == cooperative:
       emit RevocationRequested(target) over the holder's event stream
       start grace timer (holder-declared bound, capped by policy)
       ── holder releases cleanly within grace → clean handoff, best case ──
  3. on grace expiry OR revocable == forcible:
       force-break lease → backend safe-reset resource → emit OwnershipChanged
  4. resource now free → original high-priority claim proceeds (§3.4)
```

Design commitments:
- **Cooperative first, forcible only on timeout.** A well-behaved holder gets a chance to checkpoint and release cleanly (finish the in-flight DMA, flush, detach). Only a holder that won't or can't yield is force-broken.
- **The grace window is bounded by policy, declared by the holder.** A holder says "I need up to 200ms to yield safely"; policy caps how long anyone may stall a higher-priority claimant. Neither side unilaterally decides.
- **Forcible revocation always ends in safe-reset.** A force-broken resource is returned to a known-good state before the next claimant touches it — the same safe-reset path as lease-death (§3.2). The next owner never inherits the previous owner's mess.
- **`Observe` holders are never revoked** — they hold nothing exclusive, so there is nothing to take.
- **Revocation reclaims down to a floor**, of which all-or-nothing is the degenerate case. For Family A the floor is always 0 (you either hold the device or you don't) and the verb reads as "revoke." For Family B the floor is whatever quantity the holder may keep (revoke half of an 8-GB reservation back to 4 GB; partial reclaim), settled in Part 10 (`mgf-hrb-family-b-deepening.md` §2/§5). The mechanism is the same; the floor is the parameter.
- **`revoke()` below the fd, not at the fd**, is the Tier-0 #4 hardening (Part 12 §3.4): when a delegated raw channel must be invalidated *immediately* (a high-priority steal, a quarantined device, a tenant whose policy revoked their authority), the broker tears down the IOMMU mapping / unmaps the region rather than racing to close the holder's fd. The fd stays valid; the access through it faults instantly. This reconciles G4 (broker absent from the use path) with S1/S3 (instant revocation) and doubles as the preemption primitive. Implementation rides through the privileged helper (Part 7.5), deadline-bounded and verified.

This is the same shape as OS memory reclaim (ask nicely, then take), which is a sign it's the right model — and it is exactly what your future OS kernel will want natively.

---

## 3.6 Liveness binding — how a lease knows its holder lives

The lease's defining property (§3.2) requires a continuous, cheap, trustworthy liveness signal. The core consumes this as an *abstraction* (DIP); `mgf-hrb-rt` (Part 5) provides it:

- **Connection-bound (primary):** a lease is tied to the client's transport connection. Connection closed/reset (including the kernel closing it when a process dies) → instant lease loss. This is the strong signal — the OS itself reports the death, no polling.
- **Heartbeat (secondary):** for the hung-but-connected case (client alive, wedged), a periodic liveness token. Missed N intervals → lease loss. Tunable per resource criticality.
- **The core never implements liveness detection** — it subscribes to a `LivenessSource` abstraction and reacts to `holder_died(client_id)`. On your future OS, `LivenessSource` is kernel-native (process death is a kernel fact); on Linux it's connection + heartbeat. The core is identical either way (LSP/DIP).

> Two signals, because they fail differently: connection-death catches *crashes* (the common case, instant), heartbeat catches *hangs* (rarer, bounded-latency). Together they make "provably alive" actually provable, not assumed.

---

## 3.7 Crash recovery — the core itself dying (G3 under self-failure)

G3 must hold even when the core *itself* restarts. The core is **crash-only** (Part 1, reliability doctrine): no graceful shutdown path, built to be killed and resurrected at any instant.

Recovery sequence on core restart:
1. **Re-derive presence from the kernel** (`mgf-hrb-kabi` enumerate) — the hardware tells the truth about what exists; the core never trusts its own stale memory of presence.
2. **Re-establish leases from surviving connections** — the facade (Part 7) holds the client connections; clients that survived the core's restart are still connected, and their leases are reconstructed from the connection set + the resources the backend reports as still-acquired.
3. **Reconcile**: any resource the backend holds-acquired but no surviving client claims → safe-reset to `free` (a ghost from a client that died *during* the restart window). Any resource a surviving client claims but the backend doesn't hold → re-acquire or mark `faulted`.
4. **Resume** — table authoritative again; blocked new-claims unblock.

> The key insight: **the core's in-memory table is soft state, fully reconstructable from two hard sources** — the kernel (what hardware exists and what's acquired) and the connection set (who's still alive). Because nothing authoritative lives *only* in the core's memory, the core can die freely. This is what makes crash-only safe rather than reckless. (Soft-state-over-reconstructable-sources is the same discipline that makes the whole system survivable; it recurs at the facade and worker levels too.)

---

## 3.8 The raw channel grant — completing G1 at the core

Part 2.6 declared that every kind is reachable via typed ops *or* a raw channel. The core is what *grants* the raw channel, and it does so under the same ownership discipline:

```
raw(lease) →
  1. verify lease is live and held by caller        [core]
  2. verify capability permits raw access on this kind [mgf-hrb-cap]
  3. ask backend for the direct handle              [mgf-hrb-kabi]
       (Linux: dup the fd / mmap the BAR / open config space)
  4. hand the handle to the client via fd-passing   [mgf-hrb-rt]
  5. ── core now steps OUT: usage does not touch the core (G4) ──
```

The crucial property: **the core mediates the *grant* of the raw channel (slow path, ownership-checked) and then is not on the *use* of it (fast path, direct).** This is the no-bypass theorem (Part 1.5) made operational: the client gets unmediated hardware speed *and* the core's ownership table still knows it owns the channel, because the grant flowed through the core. Completeness (G1) and zero-overhead-use (G4) are satisfied simultaneously, which is the whole trick.

A raw channel is tied to its lease: lease dies → the handle is revoked/invalidated by the backend (Linux: the fd is force-closed, the mapping torn down) as part of safe-reset. You cannot retain raw access past your ownership.

---

## 3.9 Concurrency model inside the core

The core serves many workers and many clients. Its concurrency stance, chosen for reliability-then-speed:

- **The ownership table is guarded by a single-writer discipline per resource subtree**, not one global lock. Claims on `hw:/pci/**` and `hw:/usb/**` proceed in parallel (different workers, Part 7), because they touch disjoint table regions. Contention serializes only within a subtree, which is rare.
- **No blocking calls hold the table.** The fallible, slow step (backend acquire, §3.4 step 4) happens *outside* the table guard: reserve-slot (fast, guarded) → release guard → acquire (slow, unguarded) → re-take guard → commit. The table is never held across a hardware operation.
- **Lock-free reads.** `Observe`/`inspect`/`list` read a consistent snapshot without taking the write guard (RCU-style or seqlock, decided in Part 5's perf pass). Readers — the majority — never block writers and never block each other (priority #2; the read-heavy reporter/mapper workload flies).

> The discipline: hold the guard only for table mutation (microseconds), never across hardware I/O (milliseconds). This keeps the contention path fast without ever letting the table observe an inconsistent intermediate state.

---

## 3.10 SOLID report for Part 3

- **SRP — honored, strongly and deliberately.** §3.1 is almost entirely an SRP exercise: the core owns ownership-truth and *refuses* hardware, capabilities, transport, and policy. The mechanism/meaning split (core vs. policy) is the sharpest SRP+DIP boundary in the system.
- **DIP — honored, strongly.** The core depends only on abstractions: `LivenessSource`, the kabi backend trait, the capability verifier, the policy oracle. It names no concrete mechanism, touches no hardware. Fully testable against fakes.
- **OCP — honored.** New claim modes, new revocation strategies, and new kinds extend via the model's registries; the grant/revoke *machinery* is closed to modification.
- **LSP — relied upon, verified in Part 6.** The core's correctness depends on every kabi backend honoring the behavioral contract (especially safe-reset and acquire/release atomicity). The core is written to the contract; Part 6 proves backends satisfy it.
- **ISP — honored via the lattice.** `Observe`-only clients depend on (and can express) nothing beyond observation; the dangerous verbs are unreachable to them by capability and by interface.
- **Consciously declined / traded:**
  - *Acquire-before-commit (§3.4)* trades a little latency for never-lying. Reliability > performance, applied explicitly.
  - *Single-writer-per-subtree (§3.9)* is less general than a fully lock-free multi-writer table; we chose the simpler, obviously-correct discipline over a cleverer one because the table is the thing that must never be subtly wrong. Reliability > (a little) performance, and reliability > simplicity-of-the-clever-kind. The common case (disjoint subtrees) is parallel anyway, so the practical cost is near zero.

---

## 3.11 What Part 3 commits us to

- Ownership as continuously-renewed truth (leases), never as handed-out locks — so ghost ownership is structurally impossible (G3).
- A claim-mode lattice where reading never contends and exclusivity is honest (3.3).
- Atomic, partial-failure-safe grants that touch hardware last and never commit a lie (3.4).
- Cooperative-then-forcible revocation that always ends in safe-reset (3.5).
- Two-signal liveness consumed as an abstraction, kernel-native on your future OS (3.6).
- A crash-only core whose table is soft state reconstructable from kernel + connections (3.7).
- Raw-channel grants that satisfy completeness and zero-overhead-use at once (3.8) — the no-bypass theorem, operational.
- A concurrency discipline that holds the table only for mutation, never across I/O (3.9).

Part 4 builds the capability and security model the core leans on — the `mgf-hrb-cap` "is this permitted?" oracle, the trust root, and the privilege separation that keeps the dangerous code small.
# Part 4 — Capabilities & Security (`mgf-hrb-cap`)

The broker hands out privileged hardware access to arbitrary clients. That sentence is either the most dangerous thing in the system or, done right, the most trustworthy. This part makes it trustworthy. The model is **capabilities, not identities** — and it is deliberately a dry-run of the security model your future OS kernel will want, so the thinking here is an investment twice over.

**Language:** Zig. Capability verification is on the grant path (called by the core at every claim, Part 3.4/3.8) and must be fast, allocation-free, and impossible to corrupt. It sits below the socket, in the trusted computing base.

**Dependencies:** `mgf-hrb-model` (it gates `Resource`s and `Kind`s) only. It is an *abstraction* from the core's view — the core calls a `CapabilityVerifier` interface and never sees the implementation (DIP). This matters because your future OS replaces the verifier with a kernel-enforced one without the core noticing (LSP).

---

## 4.1 Why capabilities, not identities

The instinctive model — "is this user root / in group `hwaccess`?" — is an **identity/ACL** model, and it fails the broker for three reasons:

1. **Ambient authority.** If being root grants everything, then every root client can touch every device, and a compromised root client is total. Capabilities carry *only* the authority explicitly granted — a client holding "Observe `hw:/usb/bus1/dev4`" can do exactly that and nothing else, even if it runs as root.
2. **No attenuation.** ACLs can't easily express "I want to give my helper subprocess access to *one* camera and nothing else." Capabilities are attenuable by construction (§4.4): you mint a weaker token from a stronger one and hand it over.
3. **No clean revocation or expiry.** ACL membership is sticky; capabilities are leased and revocable (§4.5), tying naturally into the lease engine.

> A capability is an **unforgeable, specific, attenuable, revocable grant of one authority over one resource scope.** It answers "may the *bearer of this token* do *this* to *that*?" — not "who are you?" The shift from *who* to *what-may-be-done* is the entire security philosophy, and it is exactly what a capability-based OS kernel is built on. Building it here means you've prototyped your kernel's security before you write the kernel.

---

## 4.2 The capability token

```zig
const Capability = struct {
    scope:     UrnGlob,            // "hw:/usb/**", "hw:/pci/0000:01:00.0/fn0"
    rights:    RightSet,           // §4.3 — bitset of permitted actions
    kinds:     ?KindMask,          // optional: restrict to certain kinds within scope
    constraints: ConstraintSet,    // §4.6 — time windows, claim-mode ceilings, rate caps
    parent:    ?CapId,             // the capability this was attenuated from (§4.4)
    proof:     Unforgeable,        // §4.7 — what makes it impossible to fabricate
};
```

A capability names a **scope** (which resources, by glob), a set of **rights** (what may be done), optional **kind** and **constraint** narrowing, its **lineage** (what it was derived from), and the **proof** that it is genuine. It is a small, copyable, inspectable value — not a session, not a role, not a login.

---

## 4.3 The rights set — segregated to match ISP and the claim lattice

Rights are not a single "access" bit; they are segregated along exactly the lines the rest of the system already cuts (so the security model and the operational model agree — no impedance mismatch):

```zig
const Right = enum {
    observe,        // list, inspect, subscribe — read-only (Part 3.3 Observe)
    claim_shared,   // request Shared(rw)
    claim_exclusive,// request Exclusive
    steal,          // request Steal(priority) — preempt lower-priority holders
    reserve,        // Family B: reserve a fraction (Part 2.1)
    raw,            // obtain the raw direct channel (Part 3.8) — the sharpest right
    grant,          // mint attenuated sub-capabilities for others (§4.4)
};
```

This segregation is **ISP expressed as security**: a reporter is given a capability with `{observe}` only — it *cannot even express* a claim, let alone perform one, because it holds no right that names claiming. The read-only majority of clients are, by their tokens, structurally incapable of harm. The `raw` right is separate and sharpest: a client may be allowed to `claim_exclusive` (control via typed ops) without being allowed `raw` (unmediated register access) — two different trust levels for two different blast radii.

> Note `raw` is its own right. Granting "control this device" is not the same as granting "poke its registers directly." Typed ops are bounded by the kind's schema; raw access is bounded only by the hardware. The split lets policy hand out the safe 90% freely and gate the dangerous 10% tightly.

---

## 4.4 Attenuation — authority that only ever shrinks

The defining capability operation: from a capability you hold, mint a **weaker** one to delegate.

```zig
fn attenuate(parent: Capability, narrower: Restriction) Capability
// invariant, enforced and verifiable:
//   result.scope    ⊆ parent.scope
//   result.rights   ⊆ parent.rights
//   result.constraints ⊇ parent.constraints   (more constraints = less authority)
```

The hard invariant: **a child capability can never exceed its parent.** You may shrink scope (whole USB bus → one device), drop rights (`{observe, claim_exclusive, raw}` → `{observe}`), or add constraints (any time → only 9–5). You can never widen. This is monotone de-escalation, and it is *checkable* — given a capability and its lineage, verification confirms every link only narrowed (§4.7).

Why this is powerful for the broker:
- A VM manager holding broad device authority mints a tiny `{observe}` token for its GUI, a `{claim_exclusive}`-on-one-NIC token for a specific VM, and keeps `raw` to itself.
- A recovery tool given `{claim_exclusive, raw}` on one USB device cannot escalate to the bus, cannot touch PCIe, cannot mint `grant` tokens (unless explicitly given `grant`).
- The principle of least authority becomes the *easy* path, not the disciplined-effort path. You delegate exactly what's needed because that's what attenuation naturally produces.

---

## 4.5 Leases meet capabilities — two expiry mechanisms, one philosophy

Capabilities and leases (Part 3) are distinct but harmonized:
- A **capability** is *permission* — "you *may* claim this." It can exist before, and persist after, any actual claim.
- A **lease** is *possession* — "you *currently hold* this." It exists only while claimed and alive.

A claim requires *both*: you present a capability (proving you may) and the core grants a lease (recording that you now do). They expire by the same philosophy (bound to liveness/time, never sticky) but for different things — capability expiry revokes *permission*; lease expiry revokes *possession*. A revoked capability does not instantly break an in-flight lease (that would be unsafe mid-operation); instead it prevents *renewal* and triggers cooperative revocation (Part 3.5) of any lease that depended on it. Permission and possession decay in a coordinated, safe order.

---

## 4.6 Constraints — authority bounded in more than scope

Beyond scope and rights, a capability may carry constraints that bound *how* the authority is used:

- **Time windows** — valid only 09:00–17:00, or only for the next 5 minutes (ephemeral delegation).
- **Claim-mode ceiling** — "you may `claim` but only up to `Shared`, never `Exclusive`" (finer than the rights bitset).
- **Rate/quantity caps** — Family B: "reserve up to 2 cores"; or "at most 3 concurrent leases under this scope."
- **Revocability floor** — "any lease you take under this capability must be cooperatively revocable" (forces well-behaved holders for contended resources).

Constraints are checked at grant time (Part 3.4 step 1) and are part of the attenuation monotonicity (you can only *add* constraints downstream). They let policy express nuanced trust without new code — OCP for the security model.

---

## 4.7 Unforgeability — what makes a token genuine

A capability is worthless if a client can fabricate one. Two designs, chosen by deployment, behind one `CapabilityVerifier` abstraction (DIP — the core doesn't know which is in use):

**(a) Reference/handle capabilities (default on Linux today).** The capability is not data the client holds and presents — it is a *handle* into a table the trusted broker owns, passed to the client as an opaque, unguessable reference (and backed by an fd so the kernel enforces that only the holder can use it). The client cannot forge it because the authority lives in the broker's table, not in the token's bytes; the client merely holds a reference. Tampering is impossible because there is nothing meaningful to tamper with on the client side.

**(b) Cryptographic capabilities (for distribution / future-OS).** The capability is a signed/MAC'd token the client *can* hold and pass around (even across machines), unforgeable because the client lacks the broker's key. Used when capabilities must travel beyond a single trust domain.

> Default to (a) on Linux: it's simpler, faster (no crypto on the hot grant path), and leverages the kernel's fd-ownership semantics. Reach for (b) only when capabilities must outlive a connection or cross a boundary. On your future OS, this becomes **kernel-enforced capabilities** — the strongest form, where the kernel itself refuses to let a process act beyond its caps (the dry-run pays off as a real kernel primitive).

---

## 4.8 The trust root — bootstrapping authority (closing an open question)

Every capability descends from some root (§4.4 lineage bottoms out somewhere). *Who mints the first one?* This was an open question in earlier drafts; here is the closure.

```
              ┌────────────────────────────────────────┐
              │  ROOT CAPABILITY                          │
              │  full authority over hw:/**               │
              │  held ONLY by the broker's trust anchor   │
              │  (a small, audited bootstrap component)   │
              └───────────────────┬──────────────────────┘
                                  │ attenuates (never widens)
              ┌───────────────────┼───────────────────────┐
              ▼                   ▼                       ▼
        per-tenant /         service caps            ephemeral caps
        per-policy caps      (a VM manager's        (a one-shot
        (from mgf-hrb-policy) device authority)      delegation)
```

- **On Linux today:** the root is established at broker startup by a tiny privileged **trust-anchor** component (the only thing that begins with `hw:/**` authority). It reads a declarative **policy document** (owned by `mgf-hrb-policy`, Part 8) that says "tenant X may receive `claim_exclusive` on `hw:/pci/**`," and mints the corresponding capabilities to authenticated principals. The trust anchor is small and audited; it is the root of the chain and the highest-value target, so it does the least and is the most scrutinized.
- **Principal authentication** (proving a connecting client *is* tenant X) is delegated — mTLS, a Unix-socket peer credential (`SO_PEERCRED`), or an external identity provider — behind an `Authenticator` abstraction. The broker doesn't hardcode an auth mechanism (DIP); it maps an authenticated principal to a policy entry to a minted capability.
- **On your future OS:** the kernel *is* the trust anchor. The root capability is a kernel-issued primitive handed to the first userspace process; everything descends from it by kernel-enforced attenuation. The bootstrap problem dissolves into the kernel's init.

> The chain has exactly one root, it is held by the smallest possible audited component, and every other capability in the system is a monotone attenuation of it. There is no other source of authority — so to reason about "can client X do Y?" you follow one chain to one root. That auditability is the security dividend of the capability model.

---

## 4.9 Privilege separation — keeping the dangerous code tiny

Security architecture, restated as process structure (this dovetails with Part 7's process model):

```
   many clients (UNTRUSTED) ──socket──▶  broker service (UNPRIVILEGED, large)
                                          ├─ protocol parsing
                                          ├─ resource tree, lease table
                                          ├─ capability VERIFICATION (cap math)
                                          └─ asks ▼ for the few privileged acts
                                       tiny privileged core (TRUSTED, small)
                                          ├─ actual hardware touch (kabi)
                                          └─ trust-anchor root capability
```

- **The large, complex, attack-exposed surface holds no privilege.** Protocol parsing (the classic exploit target) runs unprivileged. Even capability *verification* — the math of checking scope/rights/lineage — is unprivileged: it decides *whether* an act is permitted but cannot itself *perform* a privileged act.
- **The privileged part is tiny and does almost nothing**: hold the root capability, perform the specific hardware operations the (unprivileged, already-verified) logic requests. It parses no untrusted input. It is small enough to audit line by line.
- **Defense in depth:** even if the unprivileged service is fully compromised, the attacker gains only the capabilities that service legitimately holds — not ambient hardware access — because the privileged core acts only on capability-checked requests. The capability model and the privilege split reinforce each other: caps limit *what authority exists*, privilege-separation limits *what code can act*.

---

## 4.10 What the security model refuses to do

Stating non-goals prevents scope creep and false guarantees (honesty, per the fidelity doctrine):
- It is **not** an audit/logging system (that's observability — events exist, but forensic logging is a separate concern layered on the event stream).
- It does **not** authenticate principals itself — it delegates to an `Authenticator` and consumes the result.
- It does **not** encrypt client data paths (the raw channel is as secure as the hardware; confidentiality of device data is the client's concern).
- It makes **no** guarantee against a malicious holder of a *legitimately granted* capability misusing the device within its grant — capabilities bound *authority*, not *intent*. (Revocation, Part 3.5, is the remedy when misuse is detected by policy.)

---

## 4.11 SOLID report for Part 4

- **ISP — honored, strongly.** The segregated rights set (§4.3) is ISP expressed as security: clients hold only the rights they need and cannot express operations they lack rights for. The separate `raw` right is the sharpest instance.
- **OCP — honored.** New rights, new constraint types (§4.6), and new authenticators extend the model without modifying verification. New deployment trust models (ref vs crypto vs kernel) are added behind the verifier abstraction.
- **DIP — honored, strongly.** `CapabilityVerifier`, `Authenticator`, and the trust anchor are all abstractions to the core. The Linux-vs-future-OS difference lives entirely behind them.
- **LSP — relied upon.** The kernel-enforced verifier (future OS) must be substitutable for the userspace one (Linux) without the core changing — same contract, stronger enforcement. Verified by the same contract suite as backends (Part 6).
- **SRP — honored.** `mgf-hrb-cap` does capability math and nothing else; authentication, policy *content*, hardware action, and logging are all elsewhere. §4.10's refusals are the SRP boundary made explicit.
- **Consciously declined / traded:** nothing significant. The one restraint: we resisted building a richer policy language *into* caps — constraints are deliberately a small fixed-extensible set, with rich policy living in `mgf-hrb-policy` (Python), because policy is meaning (changes often, Python) and caps are mechanism (must not break, Zig). Same mechanism/meaning line as Part 3.

---

## 4.12 What Part 4 commits us to

- Authority as unforgeable, specific, attenuable, revocable capabilities — never ambient identity (4.1–4.2).
- Rights segregated to match the claim lattice, with `raw` as its own sharpest right (4.3).
- Attenuation that only ever shrinks authority, making least-privilege the easy path (4.4).
- Permission (capability) and possession (lease) as distinct, coordinated, safely-decaying facts (4.5).
- Constraints that bound authority in time, mode, rate — OCP for security (4.6).
- Unforgeability by reference-handle today, crypto when distributed, kernel-enforced on your future OS (4.7).
- A single audited trust root from which all authority monotonically descends (4.8).
- Privilege separation that keeps the privileged code tiny and the exposed code powerless (4.9).
- Honest non-goals so the security claims are precise, not oversold (4.10).

Part 5 builds the runtime substrate the core and caps depend on — `mgf-hrb-rt`: the shared-memory ring ABI, fd-passing, the liveness source, and the crash-only state primitives. This is where "blazing performance" (priority #2) gets its concrete mechanism.
# Part 5 — Runtime & Transport (`mgf-hrb-rt`)

This is where priority #2 — blazing performance — stops being a principle and becomes a binary layout. `mgf-hrb-rt` is the substrate every Zig component stands on: the wire to clients, the shared-memory rings, fd-passing, the liveness signal the core consumes, and the crash-only state primitives. It is small, foundational, and brutally performance-conscious, because everything fast in the system is fast *because of* what lives here.

**Language:** Zig, entirely. This is the layer that must have zero hidden allocations, zero GC, and predictable latency. It is also the layer whose binary formats become **your future kernel's IPC and event ABI** — so its contracts are designed to be kernel-native, not Linux-shaped (the strategic note above, made concrete).

**Dependencies:** `mgf-hrb-model` only (it serializes model types). Everything else depends on *it*.

---

## 5.1 The two-plane transport — the central performance decision

The system splits all client↔broker communication into two planes with different mechanisms, because they have different cost profiles and conflating them would tax the hot one with the needs of the cold one.

```
   CONTROL PLANE  (cold, infrequent, needs auth + ordering + fd-transfer)
   ── claim · release · enumerate · subscribe-setup · capability ops ──
        mechanism: Unix domain socket (SOCK_SEQPACKET) + SCM_RIGHTS
        cost tolerance: a round-trip is fine; correctness > latency here

   DATA PLANE  (hot, high-rate, needs raw throughput)
   ── event streams · bulk readouts · telemetry ──
        mechanism: lock-free shared-memory rings + futex wakeup
        cost tolerance: ZERO per-message syscalls in steady state

   DIRECT PLANE  (hottest, the broker is not even here)
   ── MMIO/BAR/DMA on an owned resource ──
        mechanism: the passed fd / mmap'd region itself (Part 3.8)
        cost tolerance: as fast as raw hardware; broker absent
```

> The discipline: **the socket sets things up; the rings carry the firehose; the direct plane *is* the hardware.** A claim crosses the socket once (cold). The thousands of hotplug/telemetry events that follow cross the ring (no syscalls). The millions of register accesses on an owned device touch neither (direct). Each plane is matched to its frequency. This is "mediate ownership, delegate usage" expressed as three concrete transports.

---

## 5.2 The control plane — line-JSON over SOCK_STREAM (+ SCM_RIGHTS)

> **Implementation status (2026-05-26).** The deployed broker uses **`SOCK_STREAM`** with **newline-framed JSON requests/responses**. The original design called for `SOCK_SEQPACKET` (rationale preserved below — it remains the cleaner abstraction); we switched to STREAM during the skeleton broker work because line-framing was simpler to debug, the SDK's request/response cadence is well-bounded (one line up, one line down), and `SCM_RIGHTS` works identically over STREAM and SEQPACKET. The wire pins (`tests/contract/test_wire_*.py`) lock the STREAM-with-line-framing behaviour as the contract; a future move to SEQPACKET would be a protocol change, not just a transport change.

A deliberate choice among the Unix-socket types, justified because it affects the protocol's whole shape:

- **`SOCK_STREAM`** (like TCP) has no message boundaries — you must frame every message yourself and handle partial reads. The broker's `handleClient` does exactly that with `\n`-delimited JSON; the request buffer is capped at 64 KiB (`MAX_PENDING_BYTES`) to prevent unbounded buffering of malformed input.
- **`SOCK_DGRAM`** has boundaries but no connection semantics and can drop — unacceptable when a lost "release" leaks ownership.
- **`SOCK_SEQPACKET`** would give **message boundaries *and* reliable, ordered, connection-oriented delivery.** Each `send` would be one message; each `recv` exactly that message; the connection's death is detectable (which is the primary liveness signal, §5.5). It is the rare socket type that matches exactly what a control protocol wants in the abstract; we ended up at STREAM for the reasons in the status box above.

And critically: **`SCM_RIGHTS` over the socket is how file descriptors cross the boundary** — the mechanism that hands a client the direct handle (Part 3.8) and the capability reference-handle (Part 4.7). The control socket isn't just for messages; it's the channel through which *authority itself* (as fds) is transferred. STREAM + line-framing + SCM_RIGHTS together carry both the request and the granted capability in one ordered, reliable stream.

> **Future-kernel note:** SEQPACKET + SCM_RIGHTS is Linux's way of doing *ordered message-passing with capability transfer*. Your kernel can make this a first-class primitive — a message-passing IPC where capabilities (fds' successor) are transferred natively and ordering/reliability are guaranteed by the kernel rather than approximated by a socket type. The thing Linux expresses awkwardly as "a special socket flavor plus an ancillary-data hack," your kernel can express as *the* IPC primitive. This is a direct kernel-design lesson falling out of the backend.

---

## 5.3 The shared-memory ring — the data-plane ABI

The ring is the heart of the data plane and the most performance-critical binary contract in the system. It is a **single-producer, single-consumer (SPSC) lock-free ring buffer** in shared memory, one per subscription direction.

### 5.3.1 Layout

```
shared memory segment (page-aligned):
┌────────────────────────────────────────────────────────────┐
│ HEADER (one cache line, 64B, isolated to avoid false sharing) │
│   magic:u32  version:u32  ring_bytes:u32  slot_bytes:u32      │
│   ── producer cache line (64B) ──   head:u64 (write index)    │
│   ── consumer cache line (64B) ──   tail:u64 (read index)     │
│   ── control cache line (64B) ──    futex_word:u32  flags:u32 │
├────────────────────────────────────────────────────────────┤
│ SLOT RING: ring_bytes of fixed-size slots                     │
│   each slot: [len:u32][seq:u32][typed payload ...]            │
└────────────────────────────────────────────────────────────┘
```

Design choices and the reason for each:
- **`head` and `tail` live on separate cache lines.** The producer writes `head`, the consumer writes `tail`; if they shared a line, every write would bounce the line between cores (false sharing) and destroy throughput. Isolating them is the difference between a fast ring and a slow one. *(This is a hardware-reality leak: the ABI is shaped by cache-line size — exactly the kind of physical truth your kernel's IPC must also respect.)*
- **Fixed-size slots.** Variable-size framing forces the consumer to parse before it can advance — a data dependency that stalls the pipeline. Fixed slots let the consumer compute the next position arithmetically. Large payloads (rare) use an indirection slot pointing into a side region, so the common small-event case stays branch-free.
- **`seq` per slot.** A monotonic sequence number lets the consumer detect a missed/overwritten slot (ring overrun, §5.3.3) without a lock — it just checks the sequence is the one expected.
- **`magic` + `version`.** The ring is a versioned binary contract; a client built against version N refuses a version-M segment rather than misreading it. (Fidelity: never misinterpret; fail honestly.)

### 5.3.2 The lock-free protocol

Producer (broker side): write payload into slot at `head`, write `len`/`seq`, *then* publish by advancing `head` with a **release** store. Consumer: read `head` with an **acquire** load, process slots up to it, advance `tail`. The acquire/release pair is the *entire* synchronization — no mutex, no syscall — and it is correct because of the memory model's ordering guarantee: the consumer cannot see the advanced `head` before it sees the payload writes that preceded the release.

> Steady state cost: **one atomic load, one atomic store, zero syscalls, zero allocations** per event. That is the concrete meaning of "blazing." The futex (§5.3.3) is touched only when the consumer must *sleep*, never when data is flowing.

### 5.3.3 Backpressure, overrun, and wakeup — the honest-failure cases

The hard parts of any ring, handled to preserve reliability (priority #1) under load:
- **Wakeup without spinning:** when the ring is empty, the consumer sleeps on `futex_word`; the producer does a futex-wake only on the empty→non-empty transition (tracked by `flags`), so a busy ring never makes a syscall and an idle consumer never spins. Best of both.
- **Overrun (producer outruns consumer):** the ring is bounded. On a full ring, policy per subscription decides: **block** (producer waits — for telemetry where every sample matters) or **drop-oldest with a gap marker** (for high-rate events where freshness beats completeness). A dropped region is signaled by a `seq` discontinuity the consumer *will* detect, plus an explicit `overrun` event — so the consumer always *knows* it missed data (G2 honesty: never silently lose, always report the gap).
- **Slow/dead consumer:** a consumer that stops draining cannot stall the broker — its ring fills, drops per policy, and if its connection dies the whole subscription is torn down (§5.5). One bad client degrades only its own stream.

### 5.3.4 Changed-event synthesis — making "the same device, new state" one event

The kernel and the backend emit `added` and `removed` as the *only* primitives for some transitions: a USB device re-enumerating after a mode change shows up to the netlink uevent stream as `removed` (old descriptors) followed by `added` (new descriptors) — two events the consumer would have to correlate. Worse, a flicker (briefly unplugged + replugged) and a meaningful state change look identical at the raw level. A consumer driving a UI or a passthrough plan needs one `changed` event with a `previous` pointer, not two events and a correlator.

The runtime carries a **synthesizer layer** between the backend's raw events and the ring it emits to clients. On a `removed`, the synthesizer holds the snapshot in a small map keyed by `(bus, port_chain)` for a debounce window (default 1 second, tunable per subscription). If an `added` arrives within the window and `same_likely(snapshot, added.resource)` returns `SAME` or `LIKELY_SAME` (§2.4.1), the pair collapses into one `state_changed` event carrying `previous` and `current`. If the window expires, the `removed` is emitted and the synthesizer forgets the snapshot.

Key properties:

- **Synthesis is *over*, not *under*, the kernel's native signal.** When the kernel exposes a native `change` action (USB netlink `change` for driver rebind / authorisation flip / descriptor refresh), the synthesizer passes it through with `previous=null` — we don't fabricate a `previous` we didn't observe. (Same fidelity discipline: we don't lie about evidence we don't have.)
- **Per-subscription `synthesize_changes` knob.** Defaults on. A consumer wanting raw add/remove pairs (a forensic logger, a debugger) sets it off.
- **The synthesizer is cold-path** — it runs on the ring's producer side at event-emission time, not the consumer side. The hot use path is unaffected (G4).

The detailed state machine is in [`mgf-hrb-usb-worker.md`](mgf-hrb-usb-worker.md) §5.3 (where the netlink overrun story also lives) and mirrors the `mgf-usb` synthesizer at `mgf-usb/docs/design/EVENT_SYNTHESIS.md` — the algorithm has been validated against the iFig DFU sequence and tested against scripted bus flows. Resolved by [FEEDBACK paper `SDK-01`](../FEEDBACK.md).

---

## 5.4 fd-passing — moving authority across the boundary

The mechanism that makes the direct plane and capabilities work:

- A granted **raw channel** (Part 3.8) is an fd (a dup'd VFIO device fd, an mmap-able BAR fd). The broker sends it via `SCM_RIGHTS`; the kernel duplicates it into the client's fd table. The client now holds a *real kernel handle* to the hardware — the broker can even close its copy; the client's works independently. This is why use is broker-independent (survives broker restart, §5.6, G4).
- A **capability reference-handle** (Part 4.7 option a) is likewise backed by an fd: holding the fd *is* holding the capability, and the kernel's fd-ownership semantics make it unforgeable and non-transferable except by explicit re-passing.

> **Future-kernel note:** fd-passing is Linux's approximation of *capability transfer between processes*. On your kernel, this is the native capability model — you pass a capability, the kernel installs it in the recipient's capability space, attenuated if requested. Linux makes you smuggle authority as "a file descriptor in ancillary data"; your kernel can make *capability transfer* the primitive and never pretend hardware access is a "file." Another backend-friction-point becoming a kernel-design win.

---

## 5.5 The LivenessSource — providing what the core consumes

Part 3.6 said the core consumes liveness as an abstraction. `mgf-hrb-rt` *implements* that abstraction on Linux:

```zig
const LivenessSource = struct {
    // the core subscribes; rt fires holder_died(client) on either signal:
    //   (1) connection death  — the SEQPACKET socket reports EOF/RST when the
    //       client process dies. The KERNEL tells us, instantly, no polling.
    //   (2) heartbeat miss     — a liveness token expected every interval on the
    //       control plane; N missed → declared dead (catches hangs, not crashes).
    on_death: *const fn(ClientId) void,
};
```

- **Connection death is the strong, instant, kernel-sourced signal.** When a client process exits or crashes, Linux closes its sockets and the broker's `recv` returns EOF — the death is reported *by the OS*, not inferred. This is why lease-loss-on-crash is instant and certain (G3).
- **Heartbeat is the backstop for hangs** (process alive but wedged), tunable per resource criticality — a device controlling something dangerous gets a tight heartbeat; a passive sensor gets a loose one.

> **Future-kernel note:** the strong signal works because the kernel ties socket lifetime to process lifetime. On *your* kernel, make this explicit and total: a capability/lease is *owned by a process* and the kernel reclaims it on process death, natively — no heartbeat needed for the crash case at all, because the kernel is the liveness source. Heartbeats become a userspace-only concession that your kernel can largely retire. Liveness-as-a-kernel-fact is one of the cleanest things you can give your kernel that Linux can't fully give us.

---

## 5.6 Crash-only state primitives — making restart the normal path

`mgf-hrb-rt` provides the substrate that lets every Zig component (core, workers, facade) be crash-only (Parts 3.7, 7):

- **Soft state in private memory, hard state reconstructable from elsewhere.** rt offers no persistence layer on purpose — components are designed so their authoritative state lives in reconstructable sources (the kernel's view of hardware, the live connection set), never solely in a process's heap. rt's job is to make *reconstruction* fast: snapshot/rebuild helpers, connection-set enumeration, ring re-attachment.
- **Ring re-attachment across restart.** The shm segments outlive a producer restart (they're kernel-backed shared memory, not process heap). A restarted worker re-attaches to existing rings and resumes producing; surviving consumers see a `seq` continuity (or a marked gap) and carry on. **A broker-side restart does not drop a client's event stream — it pauses and resumes it.**
- **Idempotent re-attach protocol.** Re-establishing after a restart is designed to be safe to retry (the reconnect handshake is idempotent), so a restart that itself fails partway can simply be retried — recovery has no fragile half-states.

> This is the runtime-level expression of the doctrine that recurs everywhere: *nothing authoritative lives only in volatile process memory.* The core's table, the worker's claims, the facade's routing — all reconstructable. rt provides the tools that make reconstruction cheap enough that crash-only is a performance-acceptable reliability strategy, not a last resort.

---

## 5.7 What `mgf-hrb-rt` deliberately is *not*

Honesty about boundaries (per fidelity doctrine, and SRP):
- **Not a serialization framework.** It moves typed `mgf-hrb-model` values with a fixed, versioned, hand-controlled layout — not a general schema system. Generality here would cost layout control, which costs performance. Declined deliberately (priority #2 > #5 generality).
- **Not a network transport.** It is local-IPC only (Unix sockets, shared memory). Remote access, if ever needed, is a *separate* sibling that speaks to a local broker — rt stays local and fast and never grows network failure modes.
- **Not a message queue / broker-of-messages.** No durable queues, no pub/sub fan-out beyond the per-subscription ring. Those would add buffering and complexity the hot path doesn't want.

---

## 5.8 SOLID report for Part 5

- **SRP — honored.** rt does transport + liveness + crash-only substrate — arguably three things, but they are one *reason to change*: "how Zig components talk and survive locally." §5.7's refusals keep it from sprawling. If transport and liveness diverge in reason-to-change later, this is the first split to make.
- **DIP — honored.** rt exposes `LivenessSource`, ring, and fd-passing as abstractions the core/workers depend on; the Linux mechanisms (SEQPACKET, futex, SCM_RIGHTS) are hidden behind them. The future-kernel backend swaps the implementations without touching consumers.
- **OCP — partially, honestly.** The ring/socket are *versioned* (extensible by version bump) but not *pluggable* — there is one ring design, one socket type. This is deliberate: a pluggable transport abstraction would add indirection on the hottest path. **Consciously declined OCP here** in favor of performance (priority #2 > #4). We get evolvability via versioning instead of via polymorphism — the right trade for a hot, foundational layer.
- **LSP — relied upon** for the future-kernel swap: the kernel-native LivenessSource/ring/cap-transfer must satisfy the same contracts. Verified in Part 6's suite.
- **ISP — honored.** Producers depend only on the producer half of the ring; consumers on the consumer half; neither sees the other's indices.

---

## 5.9 What Part 5 commits us to

- A three-plane transport matching mechanism to frequency: socket (cold control), rings (hot data), direct fds (hottest use) — 5.1.
- SOCK_SEQPACKET + SCM_RIGHTS as the control channel that carries both requests and transferred authority — 5.2.
- A precise, cache-aware, lock-free SPSC ring ABI costing one load + one store + zero syscalls per event — 5.3.
- Honest backpressure: bounded rings that block or drop-with-a-detectable-gap, never silently lose — 5.3.3.
- fd-passing as the carrier of direct handles and capabilities, making use broker-independent — 5.4.
- A two-signal LivenessSource where crash is kernel-reported and instant, hang is heartbeat-caught — 5.5.
- Crash-only substrate where ring segments survive restarts and reconstruction is cheap — 5.6.
- Three documented future-kernel lessons: message-IPC-with-capability-transfer (5.2), capability-transfer-as-primitive (5.4), and liveness-as-a-kernel-fact (5.5) — the strategic payoff to your kernel, made explicit.

Part 6 builds the kernel seam itself — `mgf-hrb-kabi` (the abstract contract) and `mgf-hrb-linux` (the first backend) — including the behavioral/LSP contract suite that every backend, including your future kernel's, must pass. This is where the "how low we go" answer becomes a formal interface.
# Part 6 — The Kernel Seam (`mgf-hrb-kabi` + `mgf-hrb-linux`)

This is the most strategically important part for your kernel work, because **`mgf-hrb-kabi` *is* your kernel's hardware-and-capability ABI, written from the userspace side first.** Everything above this seam is kernel-agnostic; everything below it is one specific kernel. Get the seam right and your kernel port is "write one new backend"; get it wrong and the abstraction leaks and the port fights you. So this part is written with unusual care about *where exactly the line falls* and *what behavioral promises cross it.*

**Languages:** both Zig. `mgf-hrb-kabi` is a pure interface (a set of function-pointer tables / traits + the behavioral contract). `mgf-hrb-linux` is the first concrete implementation.

**The dependency law restated for this seam:** everything above (`core`, `cap`, `rt`-consumers) depends on `mgf-hrb-kabi` (the abstraction). `mgf-hrb-linux` is a *leaf* — depended upon by nothing, selected at startup. Your future `mgf-hrb-youros` is another leaf. Swapping leaves changes nothing above. **No Linux noun crosses upward** — this is the seam where that law is enforced.

---

## 6.1 What the seam abstracts — operations, not mechanisms

The seam exposes **abstract hardware operations** with kernel-agnostic meaning. It deliberately does *not* expose Linux mechanisms. The contrast is the whole point:

| Abstract operation (above the seam) | Linux mechanism (below, in `mgf-hrb-linux`) | Your kernel (below, in `mgf-hrb-youros`) |
|---|---|---|
| `enumerate(scope) -> [ResourceFact]` | walk sysfs, PCI/USB config, libudev-style logic (our code) | native resource registry query |
| `acquire(urn, mode) -> AcquireToken` | VFIO group bind / usbfs claim-interface ioctl | native exclusive-claim syscall |
| `release(token)` | VFIO unbind / usbfs release | native release |
| `map_region(token, region) -> Mapping` | mmap the VFIO device fd / BAR | native region map |
| `raw_channel(token) -> Fd` | dup the VFIO/usbfs fd (SCM_RIGHTS-able) | native capability handle |
| `reset(urn, level)` | FLR / USB port reset / driver rebind | native reset primitive |
| `watch(scope) -> EventSource` | netlink uevent socket → typed events | native event channel |
| `query_topology() -> Tree` | sysfs hierarchy + IOMMU groups + NUMA | native topology query |

Read the right two columns as **the same abstract verb, two kernels.** `acquire` *means* "give me exclusive control of this device, detached from any host driver, contained by the IOMMU." On Linux that's a specific VFIO dance; on your kernel it's whatever primitive you design — but the *meaning* and the *contract* (§6.3) are identical. The core never knows which it's talking to.

> **The single most important sentence in this whole document for your kernel:** the left column is your kernel's hardware-syscall surface, already specified, already validated by a real consumer. You do not get to design it in a vacuum and hope it's usable — you get to implement a contract that a working system already proves is sufficient and sufficient-only (nothing extraneous). That is an extraordinary position to design a kernel from.

---

## 6.2 The seam interface (the trait every backend implements)

```zig
// Every op carries a Deadline. `Deadline.none` is the escape hatch
// (purely-CPU / in-process ops); everything that crosses the kernel
// or touches hardware MUST pass a real, ceiling-checked Deadline.
// `Err.Timeout` is a typed outcome; atomicity holds through the
// timeout path (Part 12 §2.2 / D-029).
const KernelBackend = struct {
    // ---- discovery (read-only, fidelity-tagged per Part 2.8) ----
    enumerate:      *const fn(scope: UrnGlob, out: *FactSink, dl: Deadline) Err!void,
    query_topology: *const fn(dl: Deadline) Err!Tree,
    watch:          *const fn(scope: UrnGlob, sink: *EventSink, dl: Deadline) Err!WatchHandle,

    // ---- acquisition — Family A (the privileged heart) ----
    acquire:        *const fn(urn: Urn, mode: AcquireMode, dl: Deadline) Err!AcquireToken,
    release:        *const fn(token: AcquireToken, dl: Deadline) void,    // MUST NOT fail (§6.3)
    reset:          *const fn(urn: Urn, level: ResetLevel, dl: Deadline) Err!void,

    // ---- usage handles (the raw channel substrate) ----
    map_region:     *const fn(token: AcquireToken, region: RegionSpec, dl: Deadline) Err!Mapping,
    raw_channel:    *const fn(token: AcquireToken, dl: Deadline) Err!RawHandle,

    // ---- capability enforcement hook (Part 4) ----
    //   present when the kernel can enforce caps itself (your OS);
    //   null on Linux (userspace mgf-hrb-cap enforces instead).
    enforce_cap:    ?*const fn(cap: CapRef, op: Operation, dl: Deadline) Err!void,

    // ---- reservation — Family B (Part 10) ----
    //   declared on every backend so the contract is visible from day one;
    //   nullable per backend, since the first backend (mgf-hrb-linux) returns
    //   Unsupported for the apportionable family until mgf-hrb-cpu lights it up.
    //   Same honest-incompleteness pattern as enforce_cap.
    reserve:            ?*const fn(urn: Urn, qty: Quantity, strength: ReservationStrength, dl: Deadline) Err!ReservationToken,
    release_reservation:?*const fn(token: ReservationToken, dl: Deadline) void,
    adjust_reservation: ?*const fn(token: ReservationToken, new_qty: Quantity, dl: Deadline) Err!ReservationToken,

    // ---- revocation — IOMMU/mapping teardown below the fd (Part 12 §3.4) ----
    //   tears down delegated access without racing to close the holder's fd.
    //   The fd stays valid; access through it faults instantly. Implemented
    //   through the privileged helper; deadline-bounded and verified.
    revoke:         *const fn(token: AcquireToken, reason: RevokeReason, dl: Deadline) Err!void,
};
```

Notes that carry design weight:
- **Deadlines are part of the contract, not an extra.** D-029 / Part 12 §2.2: every op either completes, errors, or is abandonable within its deadline. `Err.Timeout` joins the typed error set; the trust gate (Part 5/§3.2) rejects garbage deadline values; atomicity holds through the timeout path (a `claim` whose `acquire` step times out commits no lease, leaves the resource Free). The watchdog half — killable-context execution of the blocking syscall — is the next hardening pass (Part 12 §2.2 recommendation 2/4).
- **`enforce_cap` is nullable, and that nullability is the Linux-vs-your-kernel story in one field.** On Linux the kernel can't enforce our capabilities, so it's `null` and `mgf-hrb-cap` (userspace) enforces. On your kernel, you implement it, and capability enforcement moves *into the kernel* — strictly stronger. The core calls `enforce_cap` if present, else falls back to userspace verification. **Same contract, optionally stronger enforcement** — the cleanest possible expression of "the future kernel does it better." (This is a design hook for you: decide whether your kernel enforces caps, and the broker already accommodates either answer.)
- **`release` cannot fail.** Releasing must always succeed (or safe-reset and succeed), because the lease engine calls it during crash cleanup where there is no one to handle an error. This is a *behavioral* contract (§6.3), not just a signature — and it's a constraint your kernel's release primitive must honor.
- **Nullable reservation ops carry the Family-B contract from day one** (Part 10 §3.2). `reserve` / `release_reservation` / `adjust_reservation` are declared on every backend so consumers can program against the full vocabulary; the first backend (`mgf-hrb-linux`) leaves them `null` (`Unsupported`) until `mgf-hrb-cpu` lights them up against cgroups/cpuset/hugepages. Same honest-incompleteness pattern as `enforce_cap?`.
- **`revoke` is required** (Part 12 §3.4 / Tier-0 #4). It tears down the IOMMU/mapping that backs the delegated raw channel rather than racing to close the holder's fd — the fd stays valid, access through it faults instantly. This is what reconciles G4 (broker absent from the use path) with S1/S3 (instant revocation); it doubles as preemption for fairness.
- **The seam is narrow on purpose.** Ten always-present ops (the nine original Family-A + lifecycle + `revoke`) plus four nullable ops (`enforce_cap?` + three Family-B reservation ops). Everything the broker needs, nothing it doesn't. The required core stays small; the nullable ops are growth surfaces in the *same* shape (declared, behaviour-contracted, honest about availability) — so they don't compound the implementer's burden. A narrow seam is an easy seam to implement a second time (your kernel) and an easy seam to prove correct.

### 6.2.1 `BackendCapabilities` — honest declaration of what's available

`enforce_cap?` nullability is one *binary* signal (kernel-enforces caps, or it doesn't). Real backends carry richer "what's available here" answers — a USB substrate on a host without `/dev/bus/usb` write access can do `enumerate` and `watch` but not `acquire`; an `mgf-hrb-linux` instance on a no-IOMMU host can do everything except DMA-capable passthrough. Every backend therefore exposes a structured capability report:

```zig
const BackendCapabilities = struct {
    name:           []const u8,            // "mgf-hrb-linux", "mgf-hrb-youros", ...
    version:        []const u8,
    // Op support, per the seam ops:
    enumerate:      bool,
    query_topology: bool,
    watch:          bool,                  // when false: re-enumerate, no event source
    acquire:        bool,
    release:        bool,                  // always true in a conformant backend
    reset:          bool,
    map_region:     bool,                  // false on USB (no MMIO)
    raw_channel:    bool,
    revoke:         bool,                  // always true in a conformant backend (Tier-0 #4)
    enforces_cap:   bool,                  // mirror of enforce_cap != null
    reserves:       bool,                  // Family B; mirror of reserve != null
    adjusts_reservations: bool,            // mirror of adjust_reservation != null
    // Operating mode (declared, not silent):
    mode:           enum { full, read_only, degraded_no_iommu, degraded_other },
    mode_reason:    []const u8,            // e.g. "no /dev/vfio" — operator-renderable
    // Declared latency tiers per op (p50, p99, ms) — calibrated per-host, not measured per-call.
    // Indexed by the SeamOp enum so adding ops doesn't silently shift positions.
    declared_latency: std.EnumMap(SeamOp, LatencyTier),
};
```

This is the *honest declaration* that makes "honest Unsupported" (G2) operationally useful: a caller knowing the backend's mode in advance can fail fast with a clear message ("this host runs in `read_only` mode — `acquire` will return `Unsupported`; fix: install `70-mgf-hrb.rules`") rather than wading through per-op failures. `mgf-hrb-tools doctor` (§8.6 below) is the natural consumer.

The latency tiers are **declared**, not measured per-call — same pattern that has worked in `mgf-usb`'s `backend_capabilities()`. A profiler tells you "your USB worker takes 50ms to claim an interface" without instrumenting the hot path.

---

## 6.3 The behavioral contract — making LSP real (not just signatures)

This is the crux of the whole part, and the thing most "abstraction layers" get wrong. A matching function *signature* does not make a backend substitutable. Two backends with identical signatures can behave differently under failure, and the core — written against one — breaks on the other. **LSP for this seam means a written, tested behavioral contract that every backend honors.** Signatures are checked by the compiler; *behavior* is checked by the contract suite (§6.4).

The contract specifies, per operation, the pre/postconditions and — critically — the **failure semantics**:

- **`acquire` is all-or-nothing.** On success the resource is exclusively held and IOMMU-contained; on *any* failure nothing is acquired and no partial state remains. (The core's atomic grant, Part 3.4, depends on this absolutely.)
- **`release` is total and idempotent.** It always succeeds; releasing an already-released token is a no-op, not an error. It leaves the resource in a safe, claimable state. (Crash cleanup depends on this.)
- **`reset(level)` is honest about what it achieves.** If the backend cannot perform the requested reset level (e.g. no FLR support), it must either escalate to a stronger reset that *does* achieve safe state, or fail explicitly — never return success having left the device dirty. (G2/G3: never lie about safe-reset.)
- **`enumerate`/`query_topology` are fidelity-tagged.** Every fact carries its `FieldFidelity` (Part 2.8); a backend that cannot determine a fact returns `unknown`, never a guess. (G2.)
- **`watch` is gap-honest.** If the backend's event source can drop (netlink buffer overflow), it must surface a detectable gap, never silently miss an event. (Same honesty as the ring, Part 5.3.3.)
- **`raw_channel` returns a handle that the IOMMU still contains.** Raw does not mean unprotected — the handle permits direct access *within* the device's protection domain. (Reliability: the raw channel is fast, never a way to escape containment.)
- **`revoke(token, reason)` renders delegated access inert** (Part 12 §3.4 / Tier-0 #4). It tears down the IOMMU/mapping that backs the `raw_channel` rather than racing to close the holder's fd: the fd stays valid (no use-after-revoke window the broker has to chase), and access *through* the fd faults instantly because the mapping is gone. The op MUST be deadline-bounded and the post-condition MUST be verified — the conformance suite pins that "a fault path is live within the deadline" against any backend. After `revoke`, the resource transitions to `quarantined` until a verified clean reset moves it to `free` (Part 2.7.1). This is the single op that reconciles G4 (broker absent from the use path) with S1/S3 (instant revocation); it also serves as the preemption primitive (§3.5). On the future kernel, mapping teardown is a native capability operation (kernel-feature 4 — message-IPC with native capability transfer subsumes this).
- **Every op honors its deadline.** Either complete, error with a typed code, or return `Err.Timeout` before mutating any state (D-029). A timed-out `acquire` leaves no lease and a safe, claimable resource (atomicity preserved across the timeout path); a timed-out `reset` puts the resource in `quarantined`, not `free` (Part 2.7.1). The conformance suite (§6.4) pins this against any backend via the `FakeBackend`'s declared per-op work durations (`slow_*_ms` toggles).
- **`Err.NotPermitted` carries a structured `Fix`.** A permission failure on `acquire` / `reset` / any control op carries — as part of the error envelope — a closed-enum `Fix` value (`install_udev_rule`, `add_to_plugdev`, `no_iommu_dma_capable_blocked`, `re_run_as_root_less_preferred`, `none`). The enum is matched on identity by `mgf-hrb-tools` and `mgf-hrb doctor` to render the operator-facing prose; the kabi seam itself stays Linux-noun-free (D-003 / dependency law). This is the pattern that lifts "permission denied" from a 30-message support thread to a 30-second fix; details and the canned messages live in [`mgf-hrb-usb-worker.md`](mgf-hrb-usb-worker.md) §6.

> The contract is the actual specification of your kernel's behavior. When you implement `mgf-hrb-youros`, you are not guessing what "good enough" means — you are satisfying a written contract that a real system relies on. And the contract suite (§6.4) tells you, mechanically, whether your kernel got it right. **You are getting a conformance test for your kernel's hardware ABI, for free, as a byproduct of this layer.**

---

## 6.4 The conformance suite — substitutability, verified

LSP is worthless if unenforced, so substitutability is *tested*, not trusted. `mgf-hrb-kabi` ships a **backend conformance suite**: a battery of behavioral tests written against the *abstract* contract, runnable against *any* backend.

- Run against `mgf-hrb-linux` in CI — proves the Linux backend honors the contract.
- Run against a **deterministic fake backend** (in-memory, no hardware) — this is what lets `core`, `cap`, and everything above test with zero devices. The fake is itself contract-conformant, so tests against it are meaningful.
- **Run against `mgf-hrb-youros`** when you build it — and the day it passes, your kernel's hardware ABI is *proven substitutable*, and every client and sibling above runs on your kernel unchanged. That green test suite is the moment your kernel "speaks broker."

The suite tests behavior, not implementation: acquire-then-crash leaves no leak; release-is-idempotent; reset-achieves-safe-state-or-fails; enumerate-marks-unknown-honestly; raw-channel-stays-contained; watch-surfaces-gaps. Each is a property the core relies on, encoded as a test any backend must pass.

> This is the deliverable I'd be most excited about in your position: **a portable conformance test for a hardware abstraction, that doubles as the acceptance test for your future kernel's device subsystem.** Build the kernel until the suite goes green.

---

## 6.5 `mgf-hrb-linux` — the first backend, and its honest friction points

The Linux backend implements the contract using the Level-2 mechanisms (the "how low we go" answer: direct syscalls/ioctls, never convenience libraries). Where Linux makes the contract *awkward* to satisfy, that awkwardness is a **gift to your kernel design** — each is a place your kernel can be clean. Documented friction points:

- **`acquire` requires the VFIO/IOMMU-group dance.** On Linux you can't always claim a single function — you must claim its whole IOMMU group, detach every device in it from host drivers, etc. The contract hides this (the core asks for one function), but the backend wrestles it. *Your kernel:* design device isolation at function granularity from the start, so `acquire` is genuinely per-device. (Friction → kernel feature.)
- **`enforce_cap` is `null`** — Linux can't enforce our capabilities, so userspace does it and a sufficiently privileged local actor could in principle bypass (the threat model accepts this; Part 4.9's privilege separation contains it). *Your kernel:* enforce caps in-kernel and this whole class of concern evaporates. (Friction → kernel feature.)
- **Liveness needs the heartbeat backstop** (Part 5.5) because Linux ties reclamation to fd/socket lifetime but not perfectly to all hang modes. *Your kernel:* make lease ownership a kernel-tracked process property; reclaim on death natively. (Friction → kernel feature.)
- **`watch` over netlink can drop under flood** and must surface gaps. *Your kernel:* a native event channel with explicit backpressure semantics, no silent loss. (Friction → kernel feature.)
- **Enumeration facts are scattered** across sysfs/procfs/ioctl with inconsistent freshness, forcing careful `FieldFidelity` tagging. *Your kernel:* a single authoritative resource registry with uniform freshness semantics. (Friction → kernel feature.)

> I'll keep a running "friction → kernel feature" list across the remaining parts and collect it in Part 9. It is, in effect, **a prioritized feature list for your kernel's device subsystem, derived from the actual pain of abstracting Linux.** That list is one of the most valuable byproducts of this whole exercise for you.

---

## 6.6 Backend selection — one law, no magic

How the right backend is chosen, kept deliberately boring (reliability favors boring):
- **Compile-time selection by default.** A build targets one kernel; the backend is chosen at build time, zero runtime indirection on the hot path (the seam's function-pointer table is set once at init, not dispatched per call in a way that costs). On Linux you build with `mgf-hrb-linux`; for your kernel you build with `mgf-hrb-youros`.
- **No runtime backend auto-detection, no plugin loading.** Those add failure modes and attack surface for a flexibility nobody needs (you know your kernel at build time). OCP is satisfied by *adding a backend crate and rebuilding*, not by runtime polymorphism. (Consciously declining runtime pluggability — priority #1 reliability and #2 performance over #4 flexibility.)

---

## 6.7 SOLID report for Part 6

- **LSP — honored, and this is the part where LSP is the entire point.** The behavioral contract (§6.3) + conformance suite (§6.4) make substitutability *verified*, not assumed. This is the strongest LSP treatment in the system and the reason the OS port works.
- **DIP — honored, definitively.** This *is* the dependency-inversion seam: the whole system depends on the abstract `KernelBackend`; concrete kernels are leaves. The `enforce_cap` nullable hook is DIP letting the abstraction accommodate a stronger implementation without changing consumers.
- **OCP — honored.** New backends (your kernel), new operations (added to the trait with default/`unsupported` semantics so old backends still compile), new reset levels — all additive. Runtime pluggability consciously declined (§6.6) in favor of compile-time selection.
- **ISP — honored.** The seam is narrow (nine ops); a backend implements exactly what the broker needs. Discovery, acquisition, and usage are separable groups — a hypothetical read-only backend could implement discovery and stub acquisition.
- **SRP — honored.** `mgf-hrb-kabi` is contract-only; `mgf-hrb-linux` is Linux-only; neither leaks into the other.
- **Consciously declined:** runtime backend pluggability (§6.6) — the one place we trade flexibility for reliability+performance, openly.

---

## 6.8 What Part 6 commits us to

- A narrow seam of nine abstract operations whose *meaning* is kernel-agnostic (6.1–6.2).
- A nullable `enforce_cap` hook that lets your kernel enforce capabilities in-kernel without changing anything above (6.2).
- A written *behavioral* contract — especially failure semantics — that makes LSP real, not signature-deep (6.3).
- A portable conformance suite that verifies substitutability and doubles as your kernel's device-subsystem acceptance test (6.4).
- A Linux backend at Level-2 (direct syscalls/ioctls), with its friction points logged as a feature list for your kernel (6.5).
- Boring, build-time backend selection — no runtime plugins (6.6).

Part 7 assembles these into running processes — `mgf-hrb-facade` and the per-bus workers — covering supervision, failure isolation, and how the per-bus process model (your earlier choice) maps onto the seam and the core.
# Part 7 — Process Model & Facade (`mgf-hrb-facade` + per-bus workers)

This part turns the libraries into running processes. Your earlier choice was **per-bus broker processes behind one facade**, and this part designs exactly that: how the core, the seam, the caps, and the runtime compose into a small constellation of processes whose failures are isolated and whose recovery is automatic. The shape is dictated by priority #1 (reliability) — we accept the cost of multiple processes to buy failure isolation that a single process cannot provide.

**Language:** Zig, all of it (below the socket). **Dependencies:** the facade depends on `mgf-hrb-rt` (transport, supervision primitives) and the abstract worker interface; workers depend on `core`, `kabi`, `cap`, `rt`, `model`.

---

## 7.1 The process constellation

```
                         clients (any language)
                              │  one socket connection per client
                    ┌─────────▼──────────┐
                    │   mgf-hrb-facade     │   UNPRIVILEGED
                    │   • owns the listen   │   • routes by URN scope
                    │     socket            │   • supervises workers
                    │   • routes & supervises│  • holds NO hardware privilege
                    └──┬────────┬────────┬──┘   • holds NO ownership table
            ┌──────────┘        │        └──────────┐
   ┌────────▼────────┐ ┌────────▼────────┐ ┌────────▼────────┐
   │ mgf-hrb-pcie     │ │ mgf-hrb-usb      │ │ (mgf-hrb-gpu…)  │
   │ worker (unpriv)   │ │ worker (unpriv)   │ │  future worker  │
   │ ┌──────────────┐ │ │ ┌──────────────┐ │ └─────────────────┘
   │ │ core (subtree)│ │ │ │ core (subtree)│ │  each worker:
   │ │ cap verify    │ │ │ │ cap verify    │ │   • owns ONE bus subtree
   │ │ kabi backend  │ │ │ │ kabi backend  │ │   • its own ownership table
   │ │   ↓ typed IPC │ │ │ │   ↓ typed IPC │ │   • crash-only
   │ └─────╂────────┘ │ │ └─────╂────────┘ │   • isolated failure domain
   │       ▼          │ │       ▼          │
   │ ┌──────────────┐ │ │ ┌──────────────┐ │   each worker's PRIVILEGED HELPER:
   │ │ priv helper  │ │ │ │ priv helper  │ │     • separate process, hard boundary
   │ │ (own process)│ │ │ │ (own process)│ │     • holds the elevated hardware fd
   │ │  hardware fd │ │ │ │  hardware fd │ │     • parses NO client bytes
   │ └──────────────┘ │ │ └──────────────┘ │     • accepts only typed kabi ops
   └──────────────────┘ └──────────────────┘
```

The key structural facts:
- **The facade owns no hardware and no ownership table.** It is a router and a supervisor. This is deliberate: the component every client connects to is the *least* privileged and holds the *least* state, so its compromise or crash is the least damaging.
- **Each worker owns exactly one bus subtree** (`hw:/pci/**`, `hw:/usb/**`) — its own slice of the core's logic, its own ownership table for that subtree, its own kabi backend instance. Workers share *nothing* mutable.
- **Each worker spawns a dedicated privileged helper process** (settled by Part 11; see §7.5). The helper is the only process in the worker's containment domain holding an elevated hardware handle; the unprivileged worker talks to it over a private socketpair carrying only typed kabi ops. Three independent containment walls: capability attenuation + privilege-split + process-isolation.
- **Workers are isolated failure domains.** A wedged or crashed USB worker cannot corrupt, block, or crash PCIe arbitration. This is the entire reason for the multi-process cost, and it is paid for priority #1.

> Why split the core *per worker* rather than one shared core behind the facade? Because a shared core is a shared failure domain and a shared lock domain — a bug or hang handling USB would stall PCIe. Per-worker cores mean the "single source of ownership truth" (Part 3) is *partitioned by subtree*, with each partition independently crashable and recoverable. The ownership truth is still single *per resource* (one worker owns each subtree, no overlap), so there is no split-brain — just isolation. (This partitioning is sound precisely because the namespace tree, Part 2.3, has no resource in two subtrees.)

---

## 7.2 The facade's responsibilities — router and supervisor only

SRP, sharply: the facade does two things, both structural, neither involving hardware or ownership.

**Routing:**
- Accepts client connections on the listen socket.
- Inspects each request's URN scope and routes it to the owning worker (`hw:/pci/...` → pcie worker).
- A request spanning multiple subtrees (rare; e.g. `list hw:/**`) is fanned out to each relevant worker and the results merged. The facade merges *results*, never *ownership decisions* — those stay in workers.
- Forwards the worker's response (including passed fds — the facade relays `SCM_RIGHTS` transparently) back to the client.

**Supervision:**
- Spawns workers at startup, one per registered bus kind.
- Monitors worker liveness (a worker that dies closes its facade-side channel — same kernel-sourced signal as client liveness, Part 5.5).
- **Restarts a dead worker** and triggers its crash-recovery (Part 3.7): re-derive presence from the kernel, re-establish leases from surviving client connections the facade still holds.
- Holds the *client connection set* — which is what makes worker crash-recovery possible (the surviving connections are the hard source from which leases are rebuilt).

> The facade holding the client connections is the linchpin of recovery: when a worker dies and restarts, *the clients are still connected to the facade*, so their leases can be reconstructed. The facade is the stable membrane between volatile workers and the clients. If the facade itself dies, that's the harder case — §7.4.

---

## 7.3 Why the facade holds no ownership — and the routing/ownership split

A tempting "simplification" would be to put the ownership table in the facade (one table, no partitioning). We reject it, and the reasoning is worth recording because it's a load-bearing SRP/reliability decision:

- **A central table in the facade re-creates the shared failure domain** the per-worker split exists to avoid. A bug touching the table while handling USB could corrupt PCIe ownership.
- **It would put ownership logic in the most-connected, most-exposed process** — exactly where we want the *least* logic and privilege.
- **It would serialize all arbitration through one component**, losing the per-subtree parallelism (Part 3.9) that keeps contention fast.

So: **routing lives in the facade (stateless, cheap, safe); ownership lives in workers (stateful, partitioned, isolated).** The facade knows *which worker* owns a subtree; it does not know *who owns a resource* — it asks the worker. This separation is the SRP boundary that makes the constellation both fast and robust.

---

## 7.4 The facade's own failure — the hardest reliability case

The facade is the one component every client connects through, so its death is the worst case. Handled honestly:

- **The facade is crash-only and minimal** — it holds soft state (the routing map, which is derivable from the worker registry) and the client connection set. The routing map rebuilds trivially; the connection set is the loss.
- **Direct handles survive the facade's death** (G4, Part 3.8): a client already holding a raw-channel fd keeps using its hardware *through* a facade crash, because use doesn't traverse the facade. **Ownership of in-use hardware is not lost when the facade dies** — only the ability to make *new* control requests pauses.
- **Clients reconnect after facade restart.** On reconnect, a client re-presents its capabilities and its in-flight leases are reconciled: the workers still hold the hardware (workers didn't die — only the facade did), so the worker's ownership table is the truth, and the reconnecting client is re-bound to its still-live leases.
- **A thin watchdog supervises the facade itself** (systemd, or a minimal Zig watchdog) — the classic "who watches the watcher" answered with the smallest possible always-up component whose only job is to restart the facade.

> The reliability gradient, from most to least survivable: *use of already-owned hardware* (survives everything short of hardware failure) > *workers* (crash independently, recover from kernel+connections) > *facade* (crash pauses new control ops, recovers from worker truth + reconnection) > *watchdog* (the irreducible always-up seed). Each layer's failure is bounded by the layer below it being the source of truth. **Nothing's failure is unrecoverable because nothing authoritative lives only in the thing that failed.** This is the doctrine from Parts 3, 5 reaching its full expression.

---

## 7.5 Worker internals — the tiny-privileged-core arrangement

Inside one worker, the privilege gradient from Part 4.9 is realized as concrete code separation:

```
   mgf-hrb-{bus} worker process:
   ┌────────────────────────────────────────────────┐
   │ UNPRIVILEGED region (the bulk of the code)        │
   │  • request handling from the facade               │
   │  • the core's lease engine + ownership table       │
   │  • capability verification (mgf-hrb-cap math)      │
   │  • event production into shm rings                 │
   │            │ asks for the few privileged acts      │
   │            ▼                                        │
   │ ┌──────────────────────────────────────────────┐ │
   │ │ PRIVILEGED CORE (tiny, audited)                │ │
   │ │  • the kabi backend's actual hardware touch    │ │
   │ │  • holds the elevated capability/fd to /dev/vfio│ │
   │ │  • parses NO untrusted input — receives only    │ │
   │ │    already-verified, typed acquire/reset/map ops│ │
   │ └──────────────────────────────────────────────┘ │
   └────────────────────────────────────────────────┘
```

- The privileged core is reached only by *already-capability-checked, already-typed* requests from the unprivileged region. It never sees a raw client message. Its attack surface is the handful of typed operations the seam defines (Part 6.2), not arbitrary bytes.
- **The privilege boundary is hard, not logical** (settled by the Privileged-Core Hardening pass — see `mgf-hrb-privileged-core-hardening.md` and Part 11 below). Each worker spawns a tiny separate privileged helper process and talks to it over a private socketpair carrying only typed seam ops. Earlier drafts left this as a logical boundary that *could* be hardened; the threat model (`mgf-hrb-privileged-core-hardening.md` §2) concluded the cheap defense-in-depth was worth the IPC step, especially given the helper's minimality constraint (parses no client bytes, accepts only the §6.2 typed ops). On the future kernel this collapses to thread-capabilities — see kernel-design-brief Feature 7.

> **Friction → kernel feature (continuing the Part 6 list):** on Linux, isolating the privileged core means seccomp/namespaces/helper-process gymnastics. *Your kernel:* make privilege a capability a thread either holds or doesn't, so the "tiny privileged core" is just "the only code holding the hardware capability" — no process-splitting acrobatics. Privilege separation becomes a capability-scoping question, not a process-topology one.

---

## 7.6 Startup and the trust-anchor seeding

How the constellation comes up, tying together the trust root (Part 4.8) and the process model:
1. **Watchdog** starts the **facade**.
2. The facade reads the **worker registry** (which bus kinds exist) and spawns one worker per kind.
3. Each worker initializes its **kabi backend** (compile-time selected, Part 6.6), enumerates its subtree, builds its (empty) ownership table.
4. The **trust anchor** (the only holder of the root capability, Part 4.8) seeds each worker with the capability authority for its subtree, attenuated to that subtree — a worker for `hw:/usb/**` cannot mint authority over PCIe even if compromised. (Attenuation, Part 4.4, enforced at seeding.)
5. The facade opens the **listen socket**; clients may now connect.

> Note step 4: workers are themselves capability-attenuated by subtree. The PCIe worker physically cannot issue authority over USB resources — its seeded capability doesn't reach there. The capability model (Part 4) and the process partition (this part) reinforce each other: even a fully compromised worker is bounded to its own bus by the attenuation of its seed capability. Defense in depth, where the two independent mechanisms (process isolation + capability attenuation) would both have to fail to cross a bus boundary.

---

## 7.7 Scaling shape — and what we deliberately don't build

- **One worker per bus *kind*, not per device.** PCIe with 50 functions is one worker, not 50 processes. The subtree, not the device, is the unit of isolation — the right granularity (a per-device process explosion would cost far more than it isolates).
- **No dynamic worker pools, no load-based scaling.** Hardware buses are a fixed, small set; spawning workers dynamically would add orchestration complexity for no benefit (priority #5 simplicity, and #1 reliability — fewer moving parts). The worker set is determined by the buses present, full stop.
- **Future buses are new worker kinds** (GPU, Part 9 deferred) — additive (OCP), spawned by the same facade with no facade change.

---

## 7.8 SOLID report for Part 7

- **SRP — honored, strongly.** The facade-as-router-only vs. workers-as-owners split (§7.2–7.3) is the central SRP decision of the runtime topology. The facade does routing+supervision (one reason to change: "how clients reach workers"); workers do arbitration (one reason: "how a bus is arbitrated").
- **OCP — honored.** New buses are new workers, spawned by the unchanged facade (§7.7). The facade is closed to modification, open to new worker kinds via the registry.
- **DIP — honored.** The facade depends on an abstract worker interface, not on pcie/usb concretely; workers depend on the abstract kabi/cap/liveness, not concretes. The constellation is wired from abstractions.
- **ISP — honored.** The facade's interface to a worker is narrow (route-request, lifecycle); it doesn't depend on workers' internal ownership logic.
- **LSP — relied upon.** Every worker is substitutable behind the facade's worker interface; a GPU worker drops in where the facade expects any worker.
- **Consciously declined / traded:** *multiple processes over one* (the whole part) trades simplicity and a little IPC latency for failure isolation — reliability (#1) over simplicity (#5), the defining trade of the topology, paid openly. *No dynamic scaling* (§7.7) declines a flexibility nobody needs.

---

## 7.9 What Part 7 commits us to

- A constellation: unprivileged facade (router+supervisor, no ownership) over per-bus workers (each owning one subtree's arbitration) — 7.1.
- Ownership partitioned by subtree with no overlap, so isolation without split-brain — 7.1, 7.3.
- The facade as the stable membrane holding client connections, enabling worker crash-recovery — 7.2.
- A full reliability gradient where nothing authoritative lives only in the thing that can fail — 7.4.
- The tiny-privileged-core realized as in-worker privilege separation, hardenable to a process boundary — 7.5.
- Capability-attenuated worker seeding, so process isolation and capability bounds reinforce each other — 7.6.
- Bus-kind-granular workers, no per-device explosion, no dynamic pools — 7.7.
- Another friction→kernel-feature: privilege-as-capability instead of process-splitting — 7.5.

Part 8 builds the client-facing surface — `mgf-hrb-sdk-py` and the Python siblings — applying ISP to decompose the eight verbs into role-interfaces, and showing how Python rides the socket without ever linking the Zig core.
# Part 8 — Client Surface & Python Siblings (`mgf.hrb` SDK, embedded CLI, `mgf-hrb-policy`)

This part crosses back above the socket into Python. It covers what applications actually touch: the SDK (the eight verbs, decomposed by ISP into role-interfaces), the policy sibling (meaning, as opposed to the core's mechanism), and the reference tools. The governing realization — and the cleanest consequence of the whole transport design — is that **Python never links the Zig core. It speaks the socket protocol. There is no FFI at the client boundary at all.**

**Language:** Python, all of it (above the socket). **Dependency direction:** these siblings depend on `mgf-hrb-model`'s *generated Python mirror* (types only) and on the wire protocol — never on the Zig binaries. They could be written in any language that speaks the protocol; Python is the chosen ergonomic default.

> **Shape as of 2026-05-24.** Earlier drafts of this part split the
> Python surface across three repos (`mgf-hrb-sdk-py`,
> `mgf-hrb-policy`, `mgf-hrb-tools`). The SDK now ships as a
> **federation-sibling package** in this repo at `src/mgf/hrb/`
> (`__version__ = "0.1.0"`, PEP-420 namespace under `mgf.`), with
> an **embedded operator CLI** at `src/mgf/hrb/cli/` behind the
> `mgf-hrb` console script (`scan`, `info`, `doctor` —
> FEEDBACK `TOOLS-01`). The sub-package is named so it extracts
> cleanly as a separate `mgf-hrb-cli` later if needed; nothing
> outside `mgf.hrb.cli` imports from it. `mgf-hrb-policy` remains
> a future sibling (designed; deferred). The role-interface
> decomposition and ergonomics this part describes are unchanged.

---

## 8.1 The no-FFI boundary — why this is the cleanest possible split

Earlier designs in this project (the VM manager) wrestled with a Python↔Zig FFI boundary: marshalling, manual memory ownership, error codes that must not unwind into the interpreter. **That entire class of pain does not exist here**, and the reason is the transport choice (Part 5):

```
   Python client            the boundary              Zig broker
   ─────────────            ──────────                ──────────
   mgf-hrb-sdk-py    ──SOCK_SEQPACKET messages──▶    mgf-hrb-facade
   (pure Python)     ◀──responses + SCM_RIGHTS fds──  (pure Zig)
                                  │
                     NO shared library. NO cffi. NO linked symbols.
                     NO shared memory ownership across a language ABI.
                     Just bytes on a socket and fds in ancillary data.
```

- The Python SDK **serializes a request to bytes, writes the socket, reads the response bytes, deserializes.** The only "FFI-like" thing is receiving an fd via `SCM_RIGHTS` — and Python handles that natively (`socket.recvmsg` with `CMSG`), no C extension required.
- **Memory ownership never crosses the language boundary.** The Zig side owns its memory; the Python side owns its objects; bytes are copied across the socket. There is no "who frees this buffer" question because nothing is shared — it's messaged.
- **Errors cross as typed status codes in the response**, which the SDK turns into Python exceptions. A Zig-side failure can never unwind into the interpreter, because there is no call stack shared between them — they're separate processes.

> This is the dividend of "the socket is the boundary" (Part 2/5). By choosing message-passing over linking, the Python/Zig split costs *zero* FFI complexity. The two languages meet only as bytes and fds over a kernel-mediated channel. It is the cleanest language boundary a mixed-language system can have — and it falls out for free from the transport decision made for performance reasons. (A rare case where two priorities — performance and clean-boundaries — are served by one choice.)

The one performance caveat, stated honestly: for an *in-process* client that needs the absolute lowest latency on the control path (not the data path — that's already direct), the future `mgf-hrb-sdk-zig` links natively. But the socket data plane (shm rings) is already syscall-free, so even the Python SDK gets blazing *data*; only cold control-path calls pay a socket round-trip, which is exactly the path where latency doesn't matter.

---

## 8.2 The eight verbs, decomposed by ISP into role-interfaces

Part 1 promised ISP would split the eight-verb surface so no client depends on what it doesn't use. Here it is. A monolithic `Client` with all eight verbs would force a read-only reporter to import (and be capable of expressing) `claim`, `raw`, `release` — operations it has no business touching. Instead, the surface is **role-interfaces**, each a minimal capability-shaped contract:

```python
# Role 1: Observer — the read-only majority (reporters, mappers, dashboards)
class Observer(Protocol):
    def list(self, urn_glob: str) -> list[Resource]: ...
    def inspect(self, urn: str) -> Resource: ...
    def subscribe(self, urn_glob: str) -> Iterator[Event]: ...

# Role 2: Claimant — clients that take exclusive/shared control (Family A)
class Claimant(Observer, Protocol):           # a claimant can also observe
    def claim(self, urn: str, mode: ClaimMode, priority: int | None = None) -> Lease: ...
    def release(self, lease: Lease) -> None: ...

# Role 3: RawAccessor — clients needing direct hardware (recovery tools, VMs)
class RawAccessor(Claimant, Protocol):        # raw requires having claimed
    def raw(self, lease: Lease) -> Handle: ...

# Role 4: Reserver — Family B clients (CPU/memory apportionment)
class Reserver(Observer, Protocol):           # reserve is orthogonal to claim
    def reserve(self, urn: str, quantity: Quantity, strength: ReservationStrength) -> Reservation: ...
    def adjust(self, r: Reservation, new_quantity: Quantity) -> Reservation: ...   # resize a live reservation (Part 10 §4)
    def release_reservation(self, r: Reservation) -> None: ...
```

The structure mirrors the system's real seams exactly:
- **`Observer` is the base** — everyone can observe; observing contends with nothing (Part 3.3). The read-only majority depend on *only* this and never see the dangerous verbs.
- **`Claimant` extends `Observer`** with Family-A control. **`RawAccessor` extends `Claimant`** — you cannot ask for `raw` without the ability to `claim`, because raw access is meaningless without ownership (mirrors Part 3.8: `raw` takes a `lease`).
- **`Reserver` extends `Observer`** separately — Family B is orthogonal to Family A (Part 2.1), so a Reserver is not a Claimant and vice versa. The two families' disjoint contracts (ISP at the model layer) reappear as disjoint role-interfaces (ISP at the client layer).

> The role-interfaces are **the runtime capabilities (Part 4.3) reflected at the type level.** A client granted only the `observe` right is handed an `Observer`; the SDK literally cannot offer it `claim` because the capability that backs the connection doesn't carry `claim_*`. ISP (what the type exposes) and capabilities (what the token permits) agree — a client cannot even *express* an operation it isn't permitted to perform. Type-safety and security become the same property, enforced twice (compile-time shape + runtime capability), which is defense in depth at the API surface.

---

## 8.3 Ergonomics — what the SDK adds above the raw protocol

The SDK is more than a protocol codec; it provides the Pythonic affordances that make the layer pleasant, all *above* the wire and none affecting the broker:

- **Context-managed leases** — `with client.claim(urn, Exclusive) as lease:` releases on scope exit (and the lease's liveness-binding means even a crash mid-block releases, Part 3.2; the context manager is just the *graceful* path).
- **Three-layer event API** — `monitor_fd()` / `monitor()` / `amonitor()`, all subscribing to the *same* underlying shm ring (Part 5.3). Three thin wrappers because consumers' event loops differ: a PySide6 GUI hands the fd to `QSocketNotifier`; a CLI iterates the sync `Iterator[Event]`; an asyncio service consumes the `AsyncIterator[Event]`. Locking events to one shape would force every consumer not matching it into shim code (`qasync`-style). The wrappers cost nothing — one underlying source, three views — and ensure the three layers never disagree about what fired. Detail in [`mgf-hrb-usb-worker.md`](mgf-hrb-usb-worker.md) §5.3 (consumer side) and §5.3.4 above (the synthesizer). Resolved by [FEEDBACK paper `SDK-01`](../FEEDBACK.md). **Status (2026-05-26): SHIPPED.** All three entry points are wired in `Client` (`monitor` at `_client.py:502`, `monitor_fd` at `:1174`, `amonitor` at `:1313`). Broker-side `subscribe` / `unsubscribe` with predicate filters landed in Part 13 §5.4.2 (commit `418a248`).
- **Typed resources** — `Resource`, `Event`, `Lease` are the generated Python mirrors of the Zig model types (§8.5), so the client gets real types/autocomplete, not dicts.
- **Async and sync flavors** — `Client` (sync, shipped) carries the synchronous surface; the asyncio flavor today is the `amonitor()` async iterator on `Client`. A separate `AsyncClient` class is reserved in the design but not yet implemented — `amonitor` covers the immediate event-loop use case (PySide6 with `qasync`, raw asyncio services) without forcing every other call to grow an async variant. Promotion to a full `AsyncClient` is consumer-driven (lands when an asyncio consumer needs the full surface, not before).
- **Identity helpers** — `snapshot(resource) -> Snapshot` and `same_likely(snapshot, candidate) -> Confidence` (the runtime comparator from §2.4.1) are public SDK affordances so consumers tracking a device across re-enumeration don't reinvent the algorithm. Three near-clones of the heuristic across consumers guarantees three subtly-wrong heuristics (the lesson the working `mgf-usb` library learned and codified — see `mgf-usb/docs/design/IDENTITY_HEURISTIC.md`).

> Crucially, *all* ergonomics live in Python, above the socket. The broker offers a clean protocol; the SDK makes it delightful. The broker never grows ergonomics — it stays minimal and fast. Ergonomics and mechanism are cleanly separated by the socket, the same way meaning and mechanism are (§8.4).

### 8.3.1 Threading contract — stated explicitly, not learned by hitting races

Multiple sibling consumers (a Qt GUI on the main thread, worker threads polling, an async service) will reach for the SDK simultaneously. The contract:

- **Read-side calls** — `list`, `inspect`, the synchronous parts of `claim`/`release`/`raw`/`reserve` — are safe to call concurrently from any number of threads. The SDK serialises internally where the underlying socket requires.
- **Monitor handles** — each returned `monitor()` / `amonitor()` is **single-thread-consume**. Multiple monitor *instances* across threads is safe (each gets its own subscription / ring).
- **Direct handles (raw channels)** — once delegated, the SDK is no longer in the use path (G4). Threading of an owned fd is the consumer's concern, exactly as if they had opened a kernel device file directly.

The contract is testable; the SDK ships threading tests against `FakeBackend` (§8.6) that exercise concurrent enumerate, concurrent claim on different URNs, and the misuse-detection that raises on cross-thread monitor consumption.

---

## 8.4 `mgf-hrb-policy` — meaning, where the core is mechanism

Part 3 established the core as *mechanism* and deferred *meaning* (which claim beats which, how long a grace window, who may receive what authority) to policy. `mgf-hrb-policy` is that meaning, and it lives in Python deliberately:

- **Policy changes often and is opinion-laden** — site-specific priorities, who-preempts-whom, tenant authority maps. Frequently-changing, human-readable concerns belong where they're easy to change: Python, declarative config.
- **Policy is consulted on cold paths** — at capability-seeding (startup, Part 7.6), at revocation arbitration (Part 3.5, infrequent). It is *never* on the hot data path, so Python's speed is irrelevant here. (If a policy decision were ever hot, that decision would be compiled into the core as mechanism — but by construction, decisions are cold.)
- **Policy is expressed as data the trust anchor and core consume**: a priority lattice, an authority map (principal → permitted capabilities), grace-window bounds. The core *enforces* these; policy *states* them.

```python
# illustrative policy expression — meaning, not mechanism
policy = Policy(
    authority={
        "tenant:vm-manager": grants("hw:/pci/**", {claim_exclusive, raw}),
        "tenant:reporter":   grants("hw:/**",      {observe}),
    },
    priority=lattice(critical=100, normal=50, background=10),
    grace_window_caps={"hw:/pci/**": ms(200)},   # max stall on preemption
)
```

> The policy/mechanism split is the same line as the Python/Zig split and the meaning/mechanism split — they all coincide at the socket. **Policy (Python, meaning, cold, changes often) ↔ Core (Zig, mechanism, hot, must-not-break.)** That coincidence is not accidental; it's the design recognizing that "what changes often and is opinion-laden" and "what must be fast and unbreakable" are *different concerns that belong in different languages on different sides of the boundary.* One line separates four distinct splits cleanly — a sign the boundary is in the right place.

---

## 8.5 Type mirroring — one source of truth across the language boundary

The model types (Part 2) are defined canonically in Zig (the ABI truth). The Python mirrors live in `src/mgf/hrb/domain.py` + `identity.py` as hand-written, hand-maintained projections — NOT generated today, despite the original aspiration.

- **Aspiration:** a build step that emits Python dataclasses/Protocols from the Zig `mgf-hrb-model` definitions, mechanically preventing drift between the two sides' notion of a type.
- **Reality (2026-05-26):** drift is caught by tests, not by code generation. Specifically `tests/contract/test_wire_*.py` pins every wire-shape change, and `tests/unit/mgf/hrb/test_domain.py` pins the SDK projection. The cluster C SDK forward-compat hardening (`.get`-with-default in projections, `__hash__` discipline on dataclasses) further reduces the blast radius of drift.
- **Why we haven't shipped generation yet:** the type set is small (~20 dataclasses), the wire format is line-JSON (not packed binary, where layout coupling would bite hardest), and the manual mirrors compose more naturally with `mgf.common.domain` types than a generated shape would. A generation pass is a future option, not a blocker.

> Single-source type generation is the original design's vision. The deployed surface relies on test discipline + structural `.get`-with-default to achieve the same drift-resistance honestly; generation is deferred until the type set grows past where tests can cheaply cover it.

---

## 8.6 `mgf-hrb-tools` — the reference clients that validate the whole stack

The tools are both deliverables and the end-to-end proof that the design works. Each exercises a different role-interface, so together they validate the full surface:

- **Bus-layout reporter** — `Observer` only. `list("hw:/**")`, `inspect`, render the topological tree (Part 2.3). Proves discovery + fidelity tagging end-to-end. Holds an `{observe}` capability; *cannot* claim.
- **PCIe GUI mapper** — `Observer` + `subscribe`. Live tree with ownership badges from `ownership_changed` events. Proves the event stream + ring + reconnection. PySide6, using `Client.amonitor` (the async iterator surface) on a `qasync` worker thread; full `AsyncClient` class is reserved for the day a consumer needs the full async surface.
- **USB recovery tool** — `RawAccessor`. `claim(Exclusive)` → `raw` → flash via the direct handle → `release`. Proves the full ownership + raw-channel + safe-reset-on-crash path. Holds `{observe, claim_exclusive, raw}` on a narrow scope.
- **`mgf-hrb doctor`** — operator diagnostic. Reports: which workers are spawned, which substrate each has, each worker's `BackendCapabilities` (§6.2.1) including mode (`full` / `read_only` / `degraded_no_iommu`), IOMMU presence + group counts, `/dev/vfio` and `/dev/bus/usb/*` readability, udev rule installed?, caller in the privileged group?, capability table seeded? Renders any `Fix` enum value (§6.3) as a copy-pastable shell command. The single most operator-facing surface; the answer to "the broker won't claim my device — why?" Detail and exit-code contract in [`mgf-hrb-usb-worker.md`](mgf-hrb-usb-worker.md) §7. Resolved by [FEEDBACK paper `TOOLS-01`](../FEEDBACK.md).

> The tools are deliberately chosen to span the role-interface hierarchy (Observer → Claimant → RawAccessor) and the failure-critical paths (event delivery, raw-channel-with-crash, operator triage). If they all work, the stack is proven from Python ergonomics down through the socket, the facade, a worker, the core, the cap check, the kabi backend, to real hardware — and back up the event ring. They are the living conformance test of the *whole system*, complementing the backend conformance suite (Part 6.4) that tests just the seam.

### 8.6.1 `mgf.hrb.testing` — the public test surface  *(designed; not yet shipped)*

Sibling consumers (the embedded CLI, vm-vmanager-app, figrecovery, the planned GUI) will each grow test suites that drive the SDK. Each suite needs the *same* fakes: a controllable backend that returns scripted resources / events / errors, a virtual clock so multi-step bus transitions don't depend on `sleep()`, and a `FakeResource` builder for hand-crafted descriptors. Three consumers writing three near-clones of these fakes is the same pattern that drove `mgf-usb` to ship `mgf.usb.testing` as **public** surface (D-020 there). We adopt the same answer (lands with the broker-side subscribe protocol — the fakes module is the second consumer-side surface to ship, after `Client.monitor*` is wired):

```python
from mgf.hrb.testing import (
    FakeClient,           # in-memory analog of mgf.hrb.Client; no socket, no broker
    FakeResource,         # builder for full Resource fixtures (URN, family, kind, state, fidelity, ...)
    ScriptedBus,          # virtual-clock bus: .at(t).schedule(event-or-transition); .advance(seconds)
    build_bus,            # FakeResource[...] -> ScriptedBus (convenience)
    install_fake,         # context manager: temporarily install as the SDK's broker
)
```

- **Public** — exported under the SDK's stable surface so consumers' tests can `pip install mgf-hrb-sdk-py` and use the fakes.
- **Backed by the same conformance contract** — the Zig conformance suite (Part 6.4) guarantees backend behaviour; the Python fakes are *contract-conformant* projections of the same shape, so a test against `FakeClient` makes the same assumptions a real broker satisfies.
- **`ScriptedBus` is the canonical multi-step harness** — the figrecovery-style restore flow (Normal → Recovery → DFU → flashed → Recovery → Normal, with serial vanishing in DFU) is reproducible in ~6 lines of script. Same shape as the `mgf-usb` original; same payoff (deterministic, no `sleep`, no flaky test infra).

The first-party SDK tests use the same surface — keeping the fakes honest by construction (drift would break the SDK's own suite first).

---

## 8.7 SOLID report for Part 8

- **ISP — honored, and this is the part where ISP is the point.** The role-interface decomposition (§8.2) ensures no client depends on verbs it doesn't use, and aligns the type surface with the capability model so clients can't even express unpermitted operations. Strongest ISP treatment in the system.
- **DIP — honored.** Clients depend on the role-interface `Protocol`s and the wire contract, not on any concrete broker binary. The SDK is one implementation; any language speaking the protocol is another.
- **SRP — honored.** SDK does ergonomics+protocol; policy does meaning; tools do specific jobs. The ergonomics/mechanism and meaning/mechanism splits (§8.3–8.4) are SRP across the socket.
- **OCP — honored.** New verbs extend role-interfaces additively; new tools are new clients; new policy is new data, no code change (§8.4). Sync/async are parallel extensions, neither modifying the other.
- **LSP — honored.** The future `AsyncClient` (today's `amonitor` covers the async surface) and `Client` are substitutable behind the role-interface protocols; the future `mgf-hrb-sdk-zig` is substitutable behind the same protocols (same verbs, native transport).
- **Consciously declined:** none of significance. The restraint exercised: the SDK does *not* cache resource state client-side (tempting for "performance") — because a client-side cache would risk showing stale state, violating G2 (accuracy). Clients get live answers or subscribe to events; they don't get a lying local cache. Accuracy (#3) over a minor client-side performance gain.

---

## 8.8 What Part 8 commits us to

- A no-FFI client boundary: Python speaks the socket, never links Zig, so the mixed-language split costs zero FFI complexity (8.1).
- Eight verbs decomposed into role-interfaces (Observer → Claimant → RawAccessor; Reserver) that mirror the families and the capability rights, so type-shape and permission agree (8.2).
- All ergonomics above the socket; the broker stays minimal (8.3).
- Policy as Python data expressing meaning, consumed by the Zig core as mechanism — the four splits coinciding at one boundary (8.4).
- Single-source type generation making the no-FFI boundary mechanically honest (8.5).
- Three reference tools spanning the role hierarchy as the living conformance test of the whole stack (8.6).

Part 9 assembles all eight parts: the full family/dependency map, the release phasing, the consolidated SOLID scorecard, the fidelity-guarantee verification plan, and — collected from every part — the prioritized **kernel-feature list** for your from-scratch OS.
# Part 9 — Assembly, Scorecards & the Kernel-Feature List

This part assembles the eight preceding parts into one coherent whole: the family map and dependency graph, the build phasing, the consolidated SOLID scorecard, the plan for verifying the fidelity guarantee, and — the artifact most valuable to your kernel work — the prioritized **kernel-feature list** collected from every part's friction points.

---

## 9.1 The complete family map

| Sibling | Lang | Side of socket | Role | Release 1 |
|---|---|---|---|---|
| `mgf-hrb-model` | Zig (+ generated Py) | both | resource algebra, vocabulary — depends on nothing | ✅ |
| `mgf-hrb-core` | Zig | below | the arbiter: lease engine, ownership truth, claim lattice | ✅ |
| `mgf-hrb-cap` | Zig | below | capability mint/verify/attenuate/revoke | ✅ |
| `mgf-hrb-rt` | Zig | below | transport, shm rings, fd-passing, liveness, crash-only substrate | ✅ |
| `mgf-hrb-kabi` | Zig | below | the kernel seam — abstract contract + conformance suite | ✅ |
| `mgf-hrb-linux` | Zig | below | first backend (VFIO/usbfs/sysfs/netlink) | ✅ |
| `mgf-hrb-pcie` | Zig | below | PCIe per-bus worker | ✅ |
| `mgf-hrb-usb` | Zig | below | USB per-bus worker | ✅ |
| `mgf-hrb-facade` | Zig | below | router + supervisor, holds client connections | ✅ |
| `mgf.hrb` (Python SDK) | Python | above | the client SDK — role-interfaces over the socket. Ships from `src/mgf/hrb/`, `__version__ = "0.1.0"` (federation-sibling package). | ✅ |
| `mgf.hrb.cli` (embedded operator CLI) | Python | above | `mgf-hrb` console script — `scan`, `info`, `doctor`. Lives at `src/mgf/hrb/cli/`; extracts cleanly later if needed. | ✅ |
| `mgf-hrb-policy` | Python | above | meaning: priorities, authority maps, grace bounds | ⏳ defined |
| `mgf-hrb-cpu` | Zig | below | Family-B apportionable (CPU/memory/NUMA) | ⏳ defined |
| `mgf-hrb-gpu` | Zig | below | GPU per-bus worker (same pattern) | ⏳ defined |
| `mgf-hrb-sdk-zig` | Zig | above | native client SDK for in-process / future-OS clients | ⏳ defined |
| `mgf-hrb-youros` | Zig | below | your future kernel's backend | ⏳ future |

---

## 9.2 The dependency graph (the law made visible)

```
   depends-on points DOWNWARD toward stability; nothing points up.

   PY above socket:   sdk-py     policy     tools
                         │          │          │
                         └──────────┴──────────┘
                                    │ (socket protocol + generated types)
   ═══════════════════════════════ socket ═══════════════════════════════
   ZIG below socket:           facade
                                 │
                    ┌────────────┼────────────┐
                  pcie         usb          (gpu…)        ← workers
                    └────────────┼────────────┘
                                 │ each composes:
                       core ── cap ── rt
                          \     │     /
                           \    │    /
                            kabi (abstract seam)
                                 │
                              model            ← depends on NOTHING
                                 ▲
                                 │ implemented-by (leaf, depended-on by none)
                              linux  /  youros
```

Verification that the law (Part 1.3) holds:
- `mgf-hrb-model` depends on nothing — confirmed root of stability.
- `mgf-hrb-core` depends only on `model` + abstractions (`kabi`, cap-verifier, liveness) — no concrete backend, no transport mechanism, no hardware. Testable against fakes. ✅
- `mgf-hrb-linux` / `mgf-hrb-youros` are leaves — depended on by nothing; swappable. ✅
- No Linux noun appears above `kabi` — lint-enforced. ✅
- The Python siblings depend on the *protocol*, not the Zig binaries — no FFI. ✅

---

## 9.3 Build phasing

Each phase ends with something testable; seams are designed in early phases, weight added later.

**Phase 1 — skeleton & vocabulary.** `model` + `kabi` (contract + conformance suite) + `rt` substrate + a **fake backend** passing the conformance suite. Nothing touches hardware yet, but the whole stack above can be built and tested against the fake. *Exit test: conformance suite green against the fake.*

**Phase 2 — the hard heart.** `core` lease engine + `cap` + `linux` backend implementing the seam for PCIe and USB. Claim/release/raw/safe-reset working against real hardware, single-process (no facade/workers yet). *Exit test: claim a real device, crash the client, observe self-heal (G3).*

**Phase 3 — the constellation.** `facade` + `pcie`/`usb` workers + the process model, supervision, crash-recovery. *Exit test: kill a worker mid-operation, observe isolation + recovery; kill the facade, observe in-use hardware survives (Part 7.4).*

**Phase 4 — make it usable.** `sdk-py` + `policy` + `tools`. The three reference tools validate the full stack end-to-end. *Exit test: all three tools work against real hardware (Part 8.6).*

**Deferred (post-release-1):** `cpu` (Family B), `gpu` (new worker), `sdk-zig` (native client). Contracts fixed now (Parts 2, 7, 8) so they slot in without disturbing anything above.

> The lease engine (Phase 2) is the highest-risk, highest-value component — built early and hardened hardest, because reliability (priority #1) lives there.

---

## 9.4 Consolidated SOLID scorecard

| Principle | Where it's strongest | Where consciously declined (and why) |
|---|---|---|
| **SRP** | Two-family model split (P2); core-owns-only-ownership (P3.1); facade-routes/workers-own (P7.3) | none material — SRP is cheap here and applied throughout |
| **OCP** | Open `kind` registry (P2.5); new backends (P6); new workers (P7.7); policy-as-data (P8.4) | runtime backend pluggability (P6.6) and transport pluggability (P5.8) — declined for reliability+performance; evolvability via versioning/rebuild instead |
| **LSP** | The kabi behavioral contract + conformance suite (P6.3–6.4) — verified, not assumed | none — LSP is load-bearing for the OS port, never compromised |
| **ISP** | Capability rights segregation (P4.3); client role-interfaces (P8.2); two-family disjoint contracts (P2.1) | none — ISP doubles as a security boundary, always worth it |
| **DIP** | The kabi seam (P6); liveness/cap/policy as abstractions to the core (P3, P4) | none — DIP is the spine that enables the OS port |

The pattern: **SRP, ISP, DIP, LSP are honored nearly everywhere** because they buy reliability, testability, and the OS port — all high-value per priority order. **OCP is the only principle consciously declined**, and only in two specific hot/foundational places (transport, backend selection) where polymorphic indirection would tax priority #1 and #2. Those declines are replaced by *versioning + rebuild*, which gives evolvability without runtime cost. This is "SOLID where there's high value" working exactly as intended: applied hard where it pays, declined deliberately and openly where it would tax the top priorities.

---

## 9.5 Fidelity guarantee — verification plan

The four guarantees from Part 1.4, each with its mechanism and its test:

| Guarantee | Mechanism | How it's verified |
|---|---|---|
| **G1 Completeness** (everything reachable) | typed ops *or* raw channel per kind (P2.6, P3.8); no "unreachable" category | review gate: every `Kind` declares typed-ops *and* a raw channel; a kind with an unreachable capability fails review |
| **G2 Accuracy** (never lies) | per-field `FieldFidelity` tag (P2.8); `unknown` over guessing; live state owned by core (P2.7) | fuzz test: mutate hardware state underfoot, assert descriptors never report a fact that's false (only `live`/`cached`-with-valid-invalidation/`unknown`) |
| **G3 Reliability of representation** (truth survives failure) | leases bound to liveness (P3.2); crash-only recovery from kernel+connections (P3.7, P7.4); safe-reset on loss | chaos test: kill clients/workers/facade at random points, assert no ghost ownership, no stuck `claimed`, no leaked device |
| **G4 No use-path tax** | mediate ownership / delegate usage (P3.8); direct fd, broker absent from use (P5.1) | benchmark: owned-device access latency == raw access latency within noise; broker restart does not interrupt in-use hardware |

The **no-bypass theorem** (Part 1.5) is verified transitively: if G1 holds (nothing missing) and G4 holds (no overhead), then no client has a reason to bypass — confirmed by the absence of any non-broker hardware-access path in the reference tools, and by the benchmark showing direct-through-broker == raw.

---

## 9.6 The kernel-feature list — your from-scratch OS, informed by real friction

This is the artifact collected across every part: each place Linux made the abstract contract *awkward* to satisfy is a place your kernel can be clean by design. Prioritized by leverage for your kernel's device subsystem. **This is, in effect, a specification for your kernel's hardware ABI, derived from the actual pain of abstracting a real kernel.**

| # | Kernel feature for your OS | Friction it removes on Linux | Source |
|---|---|---|---|
| 1 | **Capabilities as a native kernel primitive** — process capability-space, kernel-enforced, attenuable on transfer | userspace cap enforcement (`enforce_cap == null`); a privileged local actor can bypass | P4.7, P6.2 |
| 2 | **Lease/ownership as a kernel-tracked process property** — reclaimed on process death natively | heartbeat backstop needed because Linux only ties reclamation to fd lifetime, not all hangs | P3.6, P5.5 |
| 3 | **Per-function device isolation** from the start | VFIO forces whole-IOMMU-group claims; can't always claim one function | P6.5 |
| 4 | **Message-IPC with native capability transfer + guaranteed ordering** as *the* IPC primitive | SOCK_SEQPACKET + SCM_RIGHTS is an awkward "special socket + ancillary-data hack" | P5.2, P5.4 |
| 5 | **A single authoritative resource registry** with uniform freshness semantics | enumeration facts scattered across sysfs/procfs/ioctl with inconsistent freshness | P6.5 |
| 6 | **A native event channel** with explicit backpressure, no silent loss | netlink can drop under flood; must reconstruct gap honesty | P5.3.3, P6.5 |
| 7 | **Privilege as a thread-held capability**, not a process-topology problem | isolating the tiny privileged core needs seccomp/namespace/helper-process gymnastics | P7.5 |
| 8 | **`acquire` as a single all-or-nothing kernel operation** with native safe-reset | the VFIO/IOMMU bind/detach dance must be wrestled into atomicity | P6.3, P6.5 |

> Read this list as your kernel's device-subsystem design brief. Items 1, 2, 4, 7 cluster around **capabilities and ownership as first-class kernel concepts** — which strongly suggests your kernel wants to be **capability-based at its core**, with hardware access, IPC, and process lifetime all expressed in one capability model. That is the single biggest architectural signal this whole exercise sends to your kernel: *the broker is hard on Linux mostly because Linux's authority and lifetime models are ambient and scattered; a capability-based kernel would make most of the broker's hardest parts native.* The conformance suite (P6.4) then becomes your kernel's acceptance test — build until it's green.

---

## 9.7 Open questions carried forward (honest unknowns)

Several originally-listed questions have since closed; the remaining
open ones are kept in the same numbering for continuity. None block
Phase 1.

1. **shm ring slot sizing** — fixed slot size vs. a small set of size-classes; tune against real event-rate measurements (P5.3).
2. **Concurrency primitive for lock-free reads** — RCU-style vs. seqlock for the ownership-table read path (P3.9); decide by benchmark.
3. **Capability representation default** — reference-handle (default) is settled for Linux; confirm the crypto form's exact scheme only if/when distribution is real (P4.7).
4. ✅ **Family-B depth in `mgf-hrb-cpu`** — **closed** by the Family-B Deepening pass (Part 10 / `mgf-hrb-family-b-deepening.md`): report-only first, reservation-complete by design.
5. **Authenticator default** — `SO_PEERCRED` for local, mTLS for any remote; confirm the canonical Linux default (P4.8).
6. ✅ **Privileged-core hardening level** — **closed** by the Privileged-Core Hardening pass (Part 11 / `mgf-hrb-privileged-core-hardening.md`): Option B (hard boundary, per-worker helper) with the minimality constraint.

> The Tier-0 survivability roadmap (Part 12 / `mgf-hrb-survivability-review.md` §6.4) is the other live worklist; status as of 2026-05-24 lives in the banner at the top of that part. Tier-0 #1 (trust gate) and #3 (deadlines on the seam, D-029) have landed; the watchdog half of #3, plus #2/#4/#5, remain.

---

## 9.8 The design in one breath

A capability-secured hardware **broker**, not a passive layer: it tracks **ownership as continuously-renewed leases** so ghosts are impossible (reliability); it **mediates the claim and delegates the usage** via passed fds so owned access is as fast as raw (performance); it represents hardware **completely and honestly** with per-field fidelity and a raw escape hatch so nobody needs to bypass it (fidelity); it is built from **siblings behind a narrow kernel seam** with a verified behavioral contract so it lifts onto a new kernel by writing one backend (flexibility); and it keeps the **dangerous code tiny and the exposed code powerless** (security throughout). Zig owns everything below the socket where reliability and speed are non-negotiable; Python owns everything above where ergonomics and policy change often. The socket is the one boundary where language, privilege, meaning, and temperature all change at once — and that coincidence is the sign the boundary is right.

And, as a byproduct: a **specification and conformance test for the device subsystem of the capability-based kernel you're about to build.**

---

# Appendices — Deepening passes & survivability review

Parts 10–12 were originally appended in full to this spine. To prevent
documents from drifting apart, each is now maintained as a standalone
file under `hrb-design/` and summarized here with a pointer. Edit the
standalone files; consult this section for the executive form.

---

## Part 10 — Family-B Deepening *(canonical file: [`mgf-hrb-family-b-deepening.md`](mgf-hrb-family-b-deepening.md))*

Resolves [§9.7 open question #4](#97-open-questions-carried-forward-honest-unknowns)
— **does `mgf-hrb-cpu` start report-only, or support reservation from
day one?**

- **Decision.** Report-only first (what's *built*); reservation-complete
  by design (what's *contracted*). The seam carries the full reservation
  vocabulary from day one so adding enforcement later is not a contract
  break.
- **Conceptual move.** Family B replaces Family A's claim-mode lattice
  with a **reservation-strength axis** (`Guaranteed` / `BestEffort` /
  `Burstable`). Disjoint contracts, shared namespace.
- **Fold-back debt for the spine.** Part 2.1's claim-mode lattice
  prose still reads as universal; once Part 10 settles, the spine
  should narrow that claim to Family A.

---

## Part 11 — Privileged-Core Hardening *(canonical file: [`mgf-hrb-privileged-core-hardening.md`](mgf-hrb-privileged-core-hardening.md))*

Resolves [§9.7 open question #6](#97-open-questions-carried-forward-honest-unknowns)
— **logical privilege boundary vs. hard process boundary?**

- **Decision.** Option B — separate privileged helper process per
  worker, hard boundary, with a precise **minimality constraint**:
  the helper accepts only typed seam ops, parses no client bytes.
- **Reflected in Part 7.5** of the spine (the worker-internals
  diagram and surrounding prose are now consistent with this
  decision).

---

## Part 12 — Survivability & Adversarial-Resistance Review *(canonical file: [`mgf-hrb-survivability-review.md`](mgf-hrb-survivability-review.md))*

The staged adversarial review introducing the **S1–S5 survivability
guarantees** and the **four primitives** the ~30 findings converge on.

- **Threat model.** Both client (above) and device (below) are
  untrusted; multiple tenants are mutually untrusted; the broker is a
  membrane between two adversarial worlds.
- **Guarantees promoted to first-class.** S1 upward crash-safety, S2
  downward fault-containment, S3 tenant isolation, S4 self-fault
  containment, S5 bounded everything — peer to G1–G4.
- **Four primitives.** Deadlines (time in the seam contract),
  quarantine (a safe state for anything uncertain), revocation below
  the fd (tear down the IOMMU mapping, not the descriptor), and the
  trust gate (every client byte validated, capabilities unforgeable
  and connection-bound). Plus two disciplines: bound everything,
  re-derive don't persist.
- **Roadmap status (2026-05-26).** Tier-0 #1 (trust gate, `45efd04`),
  #2 (SO_PEERCRED + CSPRNG cap ids, `47e2cf3` / `5003d5c` / `06a0709`
  + helper privilege-drop seam at `dd69abc`), #3 (deadlines on the
  seam, `0aa9077`; supervisor watchdog kill+respawn at `dc7d481`),
  and #4 (`revoke()` below the fd, `61de2b4`) have all **landed** in
  code. Only #5 (asymmetric shared-memory trust, §3.5) remains. See
  the standalone file's top-of-document banner for the live status.

---

## Part 13 — Self-Aware Hardware Introspection *(canonical file: [`mgf-hrb-self-aware-introspection.md`](mgf-hrb-self-aware-introspection.md); current-state gap inventory: [`self-aware-introspection-current-state.md`](self-aware-introspection-current-state.md))*

A code-verified gap inventory + forward-design paper extending the
broker beyond the lease-arbitrator framing into a **near-real-time
self-aware system** that can answer "what's happening, why it
happened, how to handle that" — filed 2026-05-26.

- **Six scenarios driving the design.** Multi-client concurrent
  use + multi-client writes + driver-owner detection + driver
  load/unload + condition-filtered callbacks + bulk topology dump.
  Plus the meta requirement of broker self-awareness.
- **Verdict shape (verified against the code, not just promised).**
  Scenario 1 native; scenarios 2 / 3 / 5 / 6 partial; scenario 4
  missing. Most gaps are *additive, not architectural* — they
  fit the existing typed-op + event + capabilities model. The
  exception is scenario 4 (`module_load` / `module_unload`)
  which needs a new privileged-helper sibling (mirrors USB §U3b).
- **What the design adds.** 11 new wire ops (taking the broker
  from 9 to 20), 3 new event kinds (`driver_bound` /
  `driver_unbound` / `device_ready`), 3 new capability rights
  (`audit_read`, `load_module`, `unload_module`), per-URN
  control-verb serialisation with optimistic-concurrency
  disclosure, an in-broker audit ring buffer, and a new
  proposed sibling `mgf-hrb-modules-priv`.
- **Phasing.** Six phases that ship independently;
  cheap-additives (Phase 1) + control serialisation (Phase 4) +
  self-awareness (Phase 5) recommended first.

---

## One-paragraph executive summary

The broker's *core* (lease engine, process model, priority order,
fidelity guarantees) is soundly designed for survivability; the gaps
are at its two adversarial membranes and in its recovery contracts.
Thirty findings converge onto four primitives — **deadlines**,
**quarantine**, **revocation below the fd**, and **a single trust
gate** — plus two disciplines: **bound everything** and **re-derive
don't persist**. All hardening sits on the cold path; the hot use path
is untouched, so peak performance survives intact. The meta-
recommendation is to promote survivability to five first-class,
conformance-tested guarantees (S1–S5) peer to G1–G4 — converting
survivability from an intention into a verified property. Notably, the
two hardest Linux hardenings (deadlines, revocation-below-the-fd) are
precisely what the future capability-native kernel makes easy — so
this review also specifies two more features of `mgf-hrb-youros`.
