The OpenAPI coverage guard from main panics on a router function it does
not know and pins the set of enabled MCP tools. The enterprise AutoObserve
routes mount under /api, so autoobserve_routes joins ROUTER_PREFIXES, and
their seven operations, MCP tools by design, are listed as enterprise tools.
service_routes() nested autoobserve_routes(alert_calibration_routes(router))
in one statement. The enterprise route-permission check parses this file one
router call per statement, so it did not follow the nested call and failed.
Each call now has its own statement, as the rest of the file does.
The engine's streams are now _o2_autoobserve_*. A test writes every one of
them through MetaSink, the in-process self-reporting path, reads the stored
schema back, and checks that a user's write to the same stream is refused.
/kv refused writes and deletes under the engine's key prefix in every
build. Only an enterprise build has an engine whose marks those keys hold,
so a build without it treats them as ordinary keys.
Without the enterprise feature the AutoObserve routes were still mounted
and answered a 404 of their own, and the OpenAPI spec listed their seven
operations and tag. The handler module, the routes, the paths and the tag
now exist only in an enterprise build, next to alert calibration's, so a
build without it has no AutoObserve endpoint or API entry at all.
Each node remembered which engine streams it had bounded and never
forgot, so a stream deleted and then re-created by the engine kept the
default retention and no org partition. The check now reads the stream's
cached settings, which a delete clears, so a re-created stream is
bounded on its next write.
The drawer, map and hex labels counted checks with a monitor, so one check covered by two monitors read 1 detector while the header counted 2. Each row now carries the distinct monitors over its three checks, the same set the header totals, and every detector count is worded by one liveCopy helper.
A total shrink holds the old total while the drawer moves back to the last page. An org switch now drops that hold, and an older clamp can no longer clear or overwrite the newer org's.
Services still identical after every naming tier get #n. The number now skips any label another service already shows, so a service really named like a numbered label keeps it and every row stays distinct.
TriggerModule is stored by number. Slot 12 belongs to OncallSlackSync, now on main, so AutoObserve takes an explicit 13 that a variant added above cannot move, and a test pins it and checks every slot is distinct; the sqlite lane test now checks the stored module decodes back.
In a super cluster only the region elected to run the global scheduler
started any lane, but each region has its own AutoObserve engine row, so
the other regions never ran AutoObserve. A region the election passes
over now starts the AutoObserve lane alone, with a timeout watch scoped
to AutoObserve rows; alert and other lanes are unchanged.
Absence joins the selection the table hands the service drawer, so clicking an Absence cell opens the drawer with that detail open, like Errors and Latency, and the cell shows as pressed.
When a settled page lies past the new total, the drawer moves to the last page, refetches it under the new total and keeps that total and the dimmed rows meanwhile, so it never says there are no suggestions while some remain.
Services that share a name get their cluster, then namespace, appended. A generated name that matches another service's real name is lengthened again, and services identical in name, cluster and namespace are numbered, so rows, selection and per-service state never merge two services.
The rail decides whether more suggestions exist from the server total, not the page length. An empty page with a non-zero total keeps the count and See all, and says the top suggestions were already handled instead of claiming there are none.
The coverage tab, service drawer and suggestions rail read the live AutoObserve API, with loading, empty, failed-refresh and permission states. OEmptyState gains an opt-in tone icon.
/v2/{org_id}/autoobserve routes for entity types, coverage, coverage history, suggestions and marks, with their OpenAPI entries. /kv refuses to write or delete keys under the reserved AutoObserve prefix. Two later commits on this branch mount the routes and their OpenAPI entries, and apply the /kv guard, only in enterprise builds, so a build without enterprise has none of them.
Config types and the reserved mark keys, the core ports the enterprise
engine reads and writes through, and a scheduler lane of its own so an
engine pass never delays alert evaluation. Org cleanup lists the
engine's _meta rows as exempt: they age out by retention.