# Eve SOTA operator fleet read model — `eve.fleet-read.v1`

- **Task:** 2.5
- **Evaluated:** 2026-09-05
- **Decision:** operator-read-model-exposed
- **ADR gate:** `operator-read-model`
  (docs/adr/ADR-0076-eve-governed-delivery-lifecycle.md)
- **Tool:** `admin_agent_fleet`, registered by
  `buildWorkbenchReadOnlyToolBindings`
- **Record digest:**
  `c886a4f5fb1d57398d5df731f96a3f6cf7fec7cd233db0a3d37d2dda82285a14`

## The rule

One restrained, scannable answer to "what is the fleet doing, and what needs
me?": a fixed ten-section view that leads with a capped, severity-ordered
attention list, answers every facet task 2.5 names from rows and events read in
a single snapshot, reports a measurement this plane does not carry as an
explicit absence rather than a zero, and grants no authority over anything it
describes.

The sections are read from the module and must equal the view type’s own keys;
every facet names a field path resolved by parsing the FleetView interface and a
spec title found in the spec sources; the tool’s read-only registration is
located by slicing the two builders out of the tools module.

## What the task asks for, and where it is answered

| Facet                  | Answered at                                                                                                                                                                          | Proved by                                                                                                                                                                                                                                                   |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| queue/dependency depth | `queue.ready`, `queue.blockedByDependency`, `queue.dependencyDepth`                                                                                                                  | "counts the chain of declared dependencies, not the number of them"; "counts only the ready items still waiting on an unverified dependency"; "reports the fleet this spec actually built, not a fixture"                                                   |
| leases/ages/owners     | `leases.live`, `leases.expired`, `leases.oldestLiveAgeSeconds`, `leases.owners`                                                                                                      | "separates live holds from lapsed ones and names the owners"                                                                                                                                                                                                |
| triage                 | `triage.total`, `triage.byClass`, `triage.byDisposition`, `triage.needingHumanDecision`                                                                                              | "counts triage by class and by disposition, and finds the latest"; "counts real triage records and finds the drain that wrote them"                                                                                                                         |
| last drain             | `lastDrain.runRef`, `lastDrain.at`, `lastDrain.itemsTriaged`                                                                                                                         | "derives the last drain from the run reference the drain stamps, taking the newest"; "reports no drain seen rather than inventing one"                                                                                                                      |
| throughput             | `outcomes.windowSeconds`, `outcomes.shipped`, `outcomes.verified`                                                                                                                    | "counts only what happened inside the window"; "defaults the window to a week"                                                                                                                                                                              |
| cost                   | `cost.configured`, `cost.reason`                                                                                                                                                     | "reports cost as unconfigured rather than zero"; "never reports cost as zero, because this plane records no spend"                                                                                                                                          |
| intervention           | `intervention.humanActs`, `intervention.machineActs`, `intervention.humanShare`                                                                                                      | "measures how much of the window a human had to act in"                                                                                                                                                                                                     |
| verification rate      | `outcomes.verifiedPerShipped`, `outcomes.gapsPerShipped`, `outcomes.shipVerifyGaps`                                                                                                  | "computes verified and gap rates against what actually shipped"; "reports a rate over zero shipped items as null, not as zero"                                                                                                                              |
| rollback rate          | `outcomes.rollback.observedBackwardMoves`, `outcomes.rollback.reopenPerShipped`, `outcomes.rollback.postShipRate.configured`, `outcomes.rollback.irreversibleAfterShip.transitionId` | "refuses to report a post-ship rollback rate, and says why in the machine's own words"; "counts the backward edges that were actually taken, and zeroes the ones that were not"; "counts a real backward move, and still refuses a post-ship rollback rate" |
| kill-switch state      | `killSwitch.engaged`, `killSwitch.source`, `killSwitch.reason`                                                                                                                       | "passes the engaged state and the operator's reason straight through"; "shows the kill switch engaged, and the admission door then refuses everything"; "reads the switch fail-safe: a value it does not understand halts the fleet"                        |
| trace links            | `trace.ledgerEvents`, `trace.ledgerEventsInWindow`, `trace.links.locator`                                                                                                            | "names where every number came from, and counts the ledger it read"; "separates the whole ledger from the part inside the window"                                                                                                                           |

All 11 facets resolve to a field the `FleetView` type actually declares — the
paths are checked against the parsed interface, not against a hopeful string —
and each is asserted by a named spec case.

## What it refuses to make up

| Absence                   | Field                                       | Proved by                                                                              |
| ------------------------- | ------------------------------------------- | -------------------------------------------------------------------------------------- |
| cost                      | `cost.configured`                           | "reports cost as unconfigured rather than zero"                                        |
| post-ship-rollback-rate   | `outcomes.rollback.postShipRate.configured` | "refuses to report a post-ship rollback rate, and says why in the machine's own words" |
| rate-over-zero-shipped    | `outcomes.verifiedPerShipped`               | "reports a rate over zero shipped items as null, not as zero"                          |
| empty-queue-and-lease-age | `queue.oldestWaitSeconds`                   | "reports an empty queue age and lease age as null, not as zero seconds"                |
| no-drain-seen             | `lastDrain.runRef`                          | "reports no drain seen rather than inventing one"                                      |

## Restraint

- Sections (10, fixed): `attention`, `queue`, `leases`, `triage`, `lastDrain`,
  `outcomes`, `intervention`, `cost`, `killSwitch`, `trace`
- Attention leads the view: true
- Attention is capped at 8: true
- Attention is severity-ordered (halted > blocked > stalled > watch): true
- The section list equals the view type's own keys: true

## Authority

- Registered by `buildWorkbenchReadOnlyToolBindings`: true
- Absent from `buildWorkbenchAgentToolBindings`: true
- Registration sites in the tools module: 2, of which 0 are outside the
  read-only builder
- The kill switch arrives as an input, so the view reports it and cannot press
  it: true
- The model imports only its own siblings: true
- It takes the store as a type and never as a value: true
- The binding reads one MVCC snapshot: true
- The switch falls through ENGAGED; only `0`, `false`, `off`, `no` release it,
  so a typo halts rather than opens: true

## Honest limits

- This record closes task 2.5 only. It adds no execution isolation (2.6), no
  provider-free orchestrator model or parity proof (2.7), and no live drain or
  soak result (2.8).
- The surface is a tool binding returning a value. There is no operator UI:
  "restrained and scannable" is enforced as a fixed section set, a capped
  severity-ordered attention list, and a section order that leads with attention
  — not as a rendered layout anyone has looked at.
- Cost is reported as an explicit absence because no lease, report, ship, or
  verify event on this plane carries a token, provider, or price. Making it a
  number is task 2.8 and the model-cost registry, not this surface.
- A post-ship rollback rate does not exist because the work-item machine
  declares ship and verify irreversible. If a rollback transition is ever added,
  the section reports it without an edit here — but until then the honest answer
  is an absence, not a zero.
- The last drain is derived from the run reference the drain stamps on triage
  records. A drain whose every item advanced writes no triage and therefore
  leaves no trace on this plane, which reads as "no drain seen" rather than "no
  drain ran".
- Throughput, intervention and verification counts are computed over a
  caller-chosen window bounded to between an hour and thirty days. Nothing here
  retains history: the numbers are recomputed from the ledger on every call, so
  a ledger compaction would change them.
- The kill switch is read from the process environment of whoever calls the
  tool. It halts acquisition through the queue admission door; it does not reach
  into a drain already running in another process, which is that drain’s own
  bounded supervision from task 2.3.
