---
title: "Ops Status"
method: GET
path: "/api/v1/admin/ops/status"
tags: ["admin"]
---

# Ops Status

`GET /api/v1/admin/ops/status`

## Request

- Base URL: `https://core.mnemoverse.com`
- URL: `https://core.mnemoverse.com/api/v1/admin/ops/status`
- Auth: API key in header `X-Admin-Key`

Ops dashboard status: build identity, embedding identity vs registry, and
the fleet-wide vectorless-atom counters (FAILURE-SURFACE-2026-08-26 P0-1).

* ``embedding_identity`` is the SAME truth ``/health/ready`` reports —
  ``engine._resolve_global_embedding_stamp()``, the actual producing service.
* ``embedding_registry_active`` is the ``embedding_versions`` active row, read
  on the request pool (the table carries no RLS; boot reads it the same way).
* The atom counters go through ``storage.admin_ops_atom_counts()`` — the
  BYPASSRLS maintenance route, guarded by ``row_security_active`` on the
  same connection — and are gated by the existing
  ``ADMIN_ATOMS_AGGREGATES_ENABLED`` switch, whose config validation already
  forces a distinct maintenance DSN under multi-tenant auth. Flag off → the
  counters are null with a reason, never zero.

Failures: a database error on any read answers 503 (``MnemoError``,
retryable) — the dashboard must see "unknown", not a 500 and not a number.
A refused maintenance route (SQLSTATE ``MN001``) is a 503 that names
``MAINTENANCE_DATABASE_URL``; a pool timeout propagates to the dedicated
``asyncio.TimeoutError`` handler exactly as in ``aggregate_accounts``.

## Response `200`

Successful Response

- OpsStatusSchema: ``GET /admin/ops/status`` — one source of truth for the ops dashboard and for the "atoms without a vector" sensor (FAILURE-SURFACE-2026-08-26, P0-1). Counters and identities only: no atom content, no key material, no DSNs. The atom counters are NULLABLE on purpose, with ``atoms_unavailable_reason`` set whenever they are null — a fallback zero would read as "all good", which is the exact false negative the sensor exists to catch.
  - `git_sha` string, required: Git commit SHA of the running build ('unknown' locally).
  - `version` string, required: Application version string.
  - `uptime_s` number, nullable, required: Seconds since this process finished startup; null if the mark is missing.
  - `embedding_identity` EmbeddingIdentitySchema, required: Resolved GLOBAL embedding identity — the server-truth for provenance stamping. Exposes ONLY the model id and effective dimension (model names are not secrets); never api_url, key material, or backend internals.
    - `model` string, required: Model id of the actual producing global EmbeddingService.
    - `dim` integer, required: Effective output dimension (post-Matryoshka truncation).
  - `embedding_registry_active` EmbeddingRegistryActiveSchema, required: The ACTIVE row of the ``embedding_versions`` registry (fleet-level SSOT). Same three columns migration 018 keys the table on; never ``api_url``.
    - `model_name` string, required: Registry model id of the active row.
    - `dim` integer, required: Registry dimension of the active row.
    - `backend` string, required: Registry backend of the active row: api | local | mock.
  - `registry_matches_identity` boolean, required: True iff the registry's active (model_name, dim) equals the live embedding_identity. False when the registry has no active row.
  - `atoms_total` integer, nullable, required: Atoms across ALL organizations; null when the counters are unavailable.
  - `atoms_vectorless_total` integer, nullable, required: Atoms with EVERY vector column NULL (embedding IS NULL AND embedding_1536 IS NULL) — the sensor's headline number. Null when unavailable.
  - `atoms_vectorless_last_1h` integer, nullable, required: Vectorless atoms created in the last hour (created_at > now() - 1h).
  - `atoms_by_model` OpsAtomsByModelSchema[]: Top-5 (embedding_model, embedding_dim) buckets by count; empty when unavailable.
    - `model` string, required: Stamped embedding_model, or the literal '<null>' for unstamped atoms.
    - `dim` integer, nullable, required: Stamped embedding_dim; null when unstamped.
    - `count` integer, required: Atoms in this bucket (fleet-wide, every org).
  - `atoms_unavailable_reason` string, nullable: Set iff the atom counters are null: why, in one line.
  - `db` OpsDbPoolSchema: Request-pool occupancy, read from asyncpg without touching the database.
    - `pool_size` integer, required: Connections currently open in the request pool.
    - `pool_free` integer, required: Of those, connections idle right now.
  - `axiom` OpsAxiomSchema: Axiom log-shipper rejection counters (`mnemo.api.axiom.AxiomShipper`). A batch that gets Axiom's field-limit 400 either recovers through the bounded salvage pass (`batches_salvaged`) or is dropped whole (`batches_rejected`, `events_dropped`). `last_rejected_field` / `last_rejected_at` name the most recent field-limit 400 seen, salvaged or not: the operator hint for when it's time to regenerate `KNOWN_COLUMNS` (`scripts/fetch_axiom_columns.py --write`). `last_unparseable_at` is independent of that pair: an unparseable 400 (not a field-limit rejection at all) never touches `last_rejected_field`/`last_rejected_at`, so those two always describe the same event and never pair an old field with an unrelated newer timestamp.
    - `batches_rejected` integer, required: Batches Axiom 400'd for the field-limit that salvage could not recover.
    - `batches_salvaged` integer, required: Batches Axiom 400'd for the field-limit that salvage DID recover.
    - `events_dropped` integer, required: Total events lost across every dropped (not salvaged) batch.
    - `last_rejected_field` string, nullable, required: Field named in the most recent field-limit 400; null if none seen yet.
    - `last_rejected_at` string, nullable, required: ISO-8601 UTC timestamp of that field-limit 400; null if none seen yet. Never advanced by an unparseable 400; see last_unparseable_at.
    - `last_unparseable_at` string, nullable, required: ISO-8601 UTC timestamp of the most recent 400 that was NOT a field-limit rejection (its body did not name a field); null if none seen yet. Independent of last_rejected_at.
  - `generated_at` string, required: ISO-8601 UTC timestamp of this response.

## Other responses

- `400`: Validation error
- `401`: Unauthorized
- `403`: Forbidden
- `404`: Not found
- `429`: Rate limited
- `500`: Internal server error
- `503`: Service unavailable

---

[API](https://skmtc.dev/mnemoverse/apis/mnemoverse-core.md) · [All operations](https://skmtc.dev/mnemoverse/apis/mnemoverse-core/llms.txt) · [OpenAPI document](https://skmtc.dev/mnemoverse/apis/mnemoverse-core/revisions/1f5e0048f017?raw)
