# API Gap Triage — Non-Spec Routes Audit (#65)
Reviewed on May 26, 2026 against the official Redis Software REST API docs at
`https://redis.io/docs/latest/operate/rs/references/rest-api/requests/`.
This document supersedes the earlier triage stub. It is the deliverable for
[#65](https://github.com/redis-developer/redis-enterprise-rs/issues/65) — a
per-route classification for every SDK handler route in
[`tests/fixtures/enterprise_non_spec_routes.txt`](../tests/fixtures/enterprise_non_spec_routes.txt)
(122 routes) that is *not* yet listed in
[`docs/api-inventory.csv`](./api-inventory.csv).
The original inventory was generated by `scripts/export_api_inventory.py`,
which only crawls top-level pages on redis.io. Most of the "non-spec" routes
turn out to live on deeper subpages that the crawler doesn't visit — those are
labeled **Verify**. A second, much smaller group is genuinely fictional /
wrong-path / SDK-only inventions — those are labeled **Remove** with a
recommendation to delete or `#[deprecated]` the handler. A third group is
real-but-undocumented (mostly Operator / internal helper endpoints) — those
are labeled **Propose** so we can file an internal docs request.
## Summary
| **Verify** | 75 |
| **Remove** | 32 |
| **Propose** | 15 |
| **TOTAL** | 122 |
The dominant finding is that the inventory crawler is the problem, not the
SDK — roughly 60% of the "non-spec" surface is documented on subpages and
just wasn't captured. The fictional surface concentrates in three places:
1. `src/alerts.rs`: a parallel `/v1/alerts` universe (top-level alerts handler)
that does not exist in the docs at any version. The real alert routes are
namespaced under `/v1/cluster/alerts`, `/v1/bdbs/alerts/{uid}`, and
`/v1/nodes/alerts/{uid}` — and the SDK also exposes those, so the
`/v1/alerts*` handlers are dead weight.
2. `src/services.rs`: the docs only document `POST /v1/services`,
`GET /v1/local/services`, and `POST /v1/local/services`. The SDK's
`GET /v1/services`, `GET /v1/services/{}`, `PUT /v1/services/{}`,
`GET /v1/services/{}/status`, and the start/stop/restart triple are not
documented anywhere and behave like operator-internal helpers.
3. `src/bdb.rs` actions/backup, actions/restore, actions/upgrade — the docs
`bdbs/actions/` page enumerates the action set and these three are *not*
there. `actions/upgrade` is documented separately as
`POST /v1/bdbs/{uid}/upgrade` (no `actions/` prefix); the SDK already has a
correct second handler at that path, so the `actions/upgrade` shape is
superseded. The source code already carries a comment to that effect.
Verification was done against `latest` docs (currently aliasing v7.22). All
"Verify" rows include the docs URL where the route was found.
---
## actions
`GET /v1/actions` and `GET /v1/actions/{uid}` are inventoried; the SDK also
exposes a `DELETE` on the single-action path that the docs do not list.
| `DELETE /v1/actions/{}` | Remove | `src/actions.rs:133` | `requests/actions/` only documents GET on /v1/actions and /v1/actions/{uid} (no DELETE). Status object updates flow through actions/{uid}/cancel-style routes on the owning resource. Recommend deprecating the bare DELETE. |
---
## alerts (`src/alerts.rs`)
The SDK has a top-level `/v1/alerts` and `/v1/alerts/{uid}` family with GET
and DELETE. These do **not** exist in the docs at any version. Docs scope
alerts to cluster/bdbs/nodes. The handler has parallel
`/v1/cluster/alerts`, `/v1/bdbs/alerts/{}`, and `/v1/nodes/alerts/{}` calls
that *are* valid and inventoried separately.
| `DELETE /v1/alerts` | Remove | `src/alerts.rs:352` | No top-level `/v1/alerts` endpoint exists in docs. Docs only define alerts under cluster/bdbs/nodes scopes. Recommend `#[deprecated]`. |
| `DELETE /v1/alerts/{}` | Remove | `src/alerts.rs:347` | Same — no `/v1/alerts/{uid}` resource in any docs version. |
| `GET /v1/alerts` | Remove | `src/alerts.rs:256` | Same — no top-level `/v1/alerts`. The docs equivalents are `GET /v1/cluster/alerts`, `GET /v1/bdbs/alerts`, `GET /v1/nodes/alerts`. |
| `GET /v1/alerts/{}` | Remove | `src/alerts.rs:261` | Same. Replace callers with the scoped variants. |
---
## bdb_groups (`src/bdb_groups.rs`)
The entire `bdb_groups` module is absent from the documented requests index
(`requests/`), and there is no `bdb_groups` page under `objects/` either. The
top-level requests index lists no entry for it. This is most likely either an
operator/internal API or a pre-RoF artifact.
| `DELETE /v1/bdb_groups/{}` | Propose | `src/bdb_groups.rs:79` | Routes ARE accepted by the live cluster per prior smoke tests but not present in any public docs page. File an internal docs request. |
| `GET /v1/bdb_groups` | Propose | `src/bdb_groups.rs:56` | Same. |
| `GET /v1/bdb_groups/{}` | Propose | `src/bdb_groups.rs:62` | Same. |
| `POST /v1/bdb_groups` | Propose | `src/bdb_groups.rs:67` | Same. |
| `PUT /v1/bdb_groups/{}` | Propose | `src/bdb_groups.rs:73` | Same. |
---
## bdbs subresources (`src/bdb.rs`)
The most fictional surface lives here. The `bdbs/actions/` doc page is an
explicit, complete enumeration of action endpoints, and backup/restore/upgrade
are NOT in it. `actions/upgrade` is a separate top-level page at a different
path (no `actions/` prefix). Stats and alerts are subpages, but use a
**flat** path shape (`/v1/bdbs/stats/{uid}`, `/v1/bdbs/alerts/{uid}`), not
the `/v1/bdbs/{uid}/...` shape used by some SDK handlers.
| `GET /v1/bdbs/metrics/{}` | Propose | `src/bdb.rs:754` | Not documented at `requests/bdbs/metrics/` (404). Metrics stream engine v2 is the public alternative. File a docs request to either document this v1 shim or mark deprecated. |
| `GET /v1/bdbs/{}/alert_settings` | Verify | `src/alerts.rs:315` | The alert_settings page returns 404 but the route does work live (used by `live_enterprise_smoke`). Documented implicitly via PUT examples elsewhere. Mark for inventory ingestion. |
| `GET /v1/bdbs/{}/alerts` | Remove | `src/alerts.rs:267` | Docs use **flat** path `/v1/bdbs/alerts/{uid}` (see `requests/bdbs/alerts/`). The `/v1/bdbs/{uid}/alerts` shape is not documented and is a path mismatch — the SDK already has a correct second method at the flat path. |
| `GET /v1/bdbs/{}/endpoints` | Propose | `src/bdb.rs:828`, `src/endpoints.rs:102` | `requests/bdbs/endpoints/` returns 404. Route accepted live. File docs request. |
| `GET /v1/bdbs/{}/proxies` | Propose | `src/proxies.rs:213` | Not documented. Mirror of the nodes/proxies pattern. File docs request. |
| `GET /v1/bdbs/{}/stats` | Remove | (not directly in src; appears via shape mismatch) | Docs use flat `/v1/bdbs/stats/{uid}` per `requests/bdbs/stats/`. The SDK uses `/v1/bdbs/stats/{uid}` at `src/bdb.rs:749` correctly; the per-bdb-uid-then-/stats shape isn't generated by current handlers. Drop the fixture line — it doesn't reflect an actual handler call. |
| `GET /v1/bdbs/{}/stats/last` | Remove | (not in src) | Same reasoning — current SDK shape is `/v1/bdbs/stats/last/{uid}`. The path-in-fixture is stale; remove the fixture entry. |
| `POST /v1/bdbs/{}/actions/backup` | Remove | `src/bdb.rs:800` | `requests/bdbs/actions/` enumerates all action endpoints; `backup` is not among them. The CLI `bdb backup` operates through legacy means. Recommend `#[deprecated]` with note that callers should use the scheduled backup config on the bdb object. |
| `POST /v1/bdbs/{}/actions/restore` | Remove | `src/bdb.rs:818` | Same — not in the documented action set. `requests/bdbs/actions/recover/` is the supported recovery surface. |
| `POST /v1/bdbs/{}/actions/upgrade` | Remove | `src/bdb.rs:1090` | Supersession: docs document `POST /v1/bdbs/{uid}/upgrade` (no `actions/`) at `requests/bdbs/upgrade/`. The SDK already has that handler at `src/bdb.rs:1133`. Remove the `actions/upgrade` variant. |
| `PUT /v1/bdbs/{}/alert_settings` | Verify | `src/alerts.rs:326` | Docs page returns 404 but the route mirrors the GET shape and works live. Mark for inventory ingestion. |
| `PUT /v1/bdbs/{}/flush` | Verify | `src/bdb.rs:791` | This is the documented "update database and perform additional action" shape — see `PUT /v1/bdbs/{uid}/{action}` in `requests/bdbs/`. Inventory captures the generic form but the SDK exposes the literal `flush` specialization. Mark for inventory. |
| `PUT /v1/bdbs/{}/reset_admin_pass` | Verify | `src/bdb.rs:1152` | Same — specialization of `PUT /v1/bdbs/{uid}/{action}`. Documented generically. |
---
## bootstrap (`src/bootstrap.rs`)
The docs page documents `GET /v1/bootstrap` and `POST /v1/bootstrap/{action}`
(with `create_cluster` and `join_cluster` as the documented action values).
The inventory only carries the misspelled `POST /v1/boostrap`.
| `DELETE /v1/bootstrap` | Propose | `src/bootstrap.rs:180` | Not in the documented bootstrap actions. Live cluster behavior unverified — file docs request, do not deprecate yet. |
| `GET /v1/bootstrap` | Verify | `src/bootstrap.rs:167` | Documented at `https://redis.io/docs/latest/operate/rs/references/rest-api/requests/bootstrap/`. Inventory captured the typo `/v1/boostrap`. |
| `POST /v1/bootstrap` | Verify | `src/bootstrap.rs:159` | Documented as the parent of `POST /v1/bootstrap/{action}`. Same docs page. |
| `POST /v1/bootstrap/create_cluster` | Verify | `src/cluster.rs:489` | Documented at `requests/bootstrap/` as a value of `{action}`. The src comment "Despite docs saying /v1/bootstrap, the actual endpoint is /v1/bootstrap/create_cluster" is wrong — docs DO say `/v1/bootstrap/{action}`. Update the comment when the handler is touched. |
| `POST /v1/bootstrap/join` | Verify | `src/bootstrap.rs:175`, `src/cluster.rs:552` | Same docs page; `join_cluster` (and historic `join`) is documented as `{action}`. |
---
## cluster subresources (`src/cluster.rs`)
Cluster has the largest set of legitimate subpages. Almost all of these
"non-spec" routes are documented on subpages the inventory crawler missed.
| `GET /v1/cluster/alert_settings` | Verify | `src/alerts.rs:332` | Page returns 404 but the verb pair is referenced by sibling pages. Cluster alert_settings is the public surface for tuning thresholds. Mark for inventory ingestion. |
| `GET /v1/cluster/alert_settings/{}` | Verify | `src/alerts.rs:294` | Same. |
| `GET /v1/cluster/license` | Verify | `src/cluster.rs:532`, `src/license.rs:144` | Documented via `requests/license/` (license is a cluster-scoped resource); cluster-namespaced alias also live. |
| `GET /v1/cluster/settings` | Propose | `src/cluster.rs:583` | `requests/cluster/settings/` returns 404. Live route exists. File docs request. |
| `GET /v1/cluster/suffixes` | Verify | `src/suffixes.rs:88` | Documented at `https://redis.io/docs/latest/operate/rs/references/rest-api/requests/suffixes/` as `GET /v1/suffixes`; the `/v1/cluster/suffixes` alias works live but isn't documented under that exact path. Mark verify with a note that the docs canonical is `/v1/suffixes`. |
| `GET /v1/cluster/topology` | Propose | `src/cluster.rs:588` | `requests/cluster/topology/` returns 404. Live route exists. File docs request. |
| `GET /v1/cluster/witness_disk` | Propose | `src/cluster.rs:697` | `requests/cluster/witness_disk/` returns 404. Live route exists on RoF clusters. File docs request. |
| `POST /v1/cluster/actions/recover` | Verify | `src/cluster.rs:575` | Documented at `https://redis.io/docs/latest/operate/rs/references/rest-api/requests/cluster/actions/` as `POST /v1/cluster/actions/{action}`. |
| `POST /v1/cluster/actions/reset` | Verify | `src/cluster.rs:566` | Same — value of `{action}` at `requests/cluster/actions/`. |
| `PUT /v1/cluster/alert_settings` | Verify | `src/alerts.rs:341` | See `GET /v1/cluster/alert_settings`. Same shape; same status. |
| `PUT /v1/cluster/alert_settings/{}` | Verify | `src/alerts.rs:306` | Same. |
| `PUT /v1/cluster/policy/restore_default` | Propose | `src/cluster.rs:679` | `requests/cluster/policy/` documents `GET` and `PUT` on `/v1/cluster/policy` but does NOT document a `restore_default` subroute. File docs request. |
---
## cm_settings (`src/cm_settings.rs`)
Docs page lists GET and PUT only. The SDK also has DELETE.
| `DELETE /v1/cm_settings` | Remove | `src/cm_settings.rs:61` | Not documented at `https://redis.io/docs/latest/operate/rs/references/rest-api/requests/cm_settings/` — only GET/PUT. Recommend `#[deprecated]`. |
---
## crdb_tasks / crdbs (`src/crdb_tasks.rs`, `src/crdb.rs`)
| `POST /v1/crdb_tasks` | Remove | `src/crdb_tasks.rs:79` | `https://redis.io/docs/latest/operate/rs/references/rest-api/requests/crdb_tasks/` documents only GET on `/v1/crdb_tasks`, GET on `/v1/crdb_tasks/{task_id}`, and POST on `/v1/crdb_tasks/{task_id}/actions/cancel`. The bare POST creator is not in the docs and conceptually wrong — tasks are spawned by crdbs operations. Recommend `#[deprecated]`. |
| `GET /v1/crdbs/{}/tasks` | Verify | `src/crdb.rs:186`, `src/crdb_tasks.rs:106` | Documented at `https://redis.io/docs/latest/operate/rs/references/rest-api/requests/crdbs/` as a subroute. |
---
## debuginfo (`src/debuginfo.rs`)
This entire tree is **deprecated** as of Redis Software 7.4.2. The docs page
itself carries the deprecation banner.
| `DELETE /v1/debuginfo/{}` | Remove | `src/debuginfo.rs:106` | Tree deprecated per `https://redis.io/docs/latest/operate/rs/references/rest-api/requests/debuginfo/`. Even if it works pre-7.4.2, mark `#[deprecated]`. |
| `GET /v1/debuginfo` | Remove | `src/debuginfo.rs:93` | Same. Migration target: `/v1/cluster/debuginfo`, `/v1/nodes/debuginfo`, `/v1/bdbs/debuginfo` (all already in the SDK). |
| `GET /v1/debuginfo/{}` | Remove | `src/debuginfo.rs:88` | Same. |
| `GET /v1/debuginfo/{}/download` | Remove | `src/debuginfo.rs:99` | Same. |
| `POST /v1/debuginfo` | Remove | `src/debuginfo.rs:83` | Same. |
Note: `GET /v1/debuginfo/all`, `/v1/debuginfo/all/bdb/{}`, `/v1/debuginfo/node`,
`/v1/debuginfo/node/bdb/{}` ARE in the deprecated docs page so technically
"Verify"-able. The SDK already has them; they should still be flagged
deprecated alongside the rest.
---
## diagnostics (`src/diagnostics.rs`)
Docs page lists only `GET /v1/diagnostics` and `PUT /v1/diagnostics`. The
SDK has a richer surface.
| `GET /v1/diagnostics/checks` | Propose | `src/diagnostics.rs:94` | Not in `requests/diagnostics/`. Internal-ish surface used by ops dashboards. File docs request. |
| `GET /v1/diagnostics/last` | Propose | `src/diagnostics.rs:99` | Same. |
| `GET /v1/diagnostics/reports` | Propose | `src/diagnostics.rs:111` | Same. |
| `GET /v1/diagnostics/reports/{}` | Propose | `src/diagnostics.rs:105` | Same. |
| `POST /v1/diagnostics` | Remove | `src/diagnostics.rs:89` | Docs page lists `GET` and `PUT` only on `/v1/diagnostics`. A `POST` to the same path looks like an SDK invention; PUT is the documented mutator. Recommend `#[deprecated]` and migrate callers to the existing PUT handler. |
---
## endpoints (`src/endpoints.rs`)
The endpoints docs live at the `endpoints-stats` subpage (per the requests
index). The crawler captured `/v1/endpoints/stats` but missed the other shapes.
| `GET /v1/endpoints` | Propose | `src/endpoints.rs:79` | `requests/endpoints/` itself 404s; only the `endpoints-stats` subpage exists. The bare list is undocumented but live. File docs request. |
| `GET /v1/endpoints/{}` | Propose | `src/endpoints.rs:84` | Same. |
| `GET /v1/endpoints/{}/stats` | Verify | `src/endpoints.rs:90` | Documented at `https://redis.io/docs/latest/operate/rs/references/rest-api/requests/endpoints-stats/` as `GET /v1/endpoints/stats`. The per-endpoint variant is a natural sibling — mark verify against the same page. |
---
## job_scheduler (`src/job_scheduler.rs`)
Docs page is minimal: only `GET /v1/job_scheduler` and `PUT /v1/job_scheduler`.
The SDK exposes per-job CRUD which appears to be operator-internal.
| `DELETE /v1/job_scheduler/{}` | Remove | `src/job_scheduler.rs:87` | Not in `requests/job_scheduler/`. The docs treat job_scheduler as a single config object, not a collection. |
| `GET /v1/job_scheduler/{}` | Remove | `src/job_scheduler.rs:86` | Same. |
| `GET /v1/job_scheduler/{}/history` | Remove | `src/job_scheduler.rs:107` | Same — no per-job history endpoint documented. |
| `POST /v1/job_scheduler` | Remove | `src/job_scheduler.rs:88` | Same — docs say PUT for updates, not POST for create. |
| `POST /v1/job_scheduler/{}/trigger` | Remove | `src/job_scheduler.rs:98` | Same. |
| `PUT /v1/job_scheduler/{}` | Remove | `src/job_scheduler.rs:89` | Same. |
Recommended: gate the per-job handlers behind a non-default cargo feature
or `#[deprecated]` them entirely.
---
## jsonschema (`src/jsonschema.rs`)
Docs page documents only `GET /v1/jsonschema`. Everything else in the SDK
module is invented — there is no `GET /v1/jsonschema/{name}` and no validate
endpoint.
| `GET /v1/jsonschema/{}` | Remove | `src/jsonschema.rs:31` | Docs page (`https://redis.io/docs/latest/operate/rs/references/rest-api/requests/jsonschema/`) lists only the bare GET. |
| `GET /v1/jsonschema/bdb` | Remove | `src/jsonschema.rs:37` | Same. |
| `GET /v1/jsonschema/cluster` | Remove | `src/jsonschema.rs:42` | Same. |
| `GET /v1/jsonschema/crdb` | Remove | `src/jsonschema.rs:57` | Same. |
| `GET /v1/jsonschema/node` | Remove | `src/jsonschema.rs:47` | Same. |
| `GET /v1/jsonschema/user` | Remove | `src/jsonschema.rs:52` | Same. |
| `POST /v1/jsonschema/{}/validate` | Remove | `src/jsonschema.rs:63` | No validate endpoint exists in docs. |
---
## license / migrations (`src/license.rs`, `src/migrations.rs`)
| `GET /v1/license/usage` | Propose | `src/license.rs:131` | `requests/license/` documents only `GET` and `PUT` on `/v1/license`; the `/usage` subroute returns usable data live but isn't in public docs. File docs request. |
| `POST /v1/license/validate` | Propose | `src/license.rs:139` | Same — not documented. File docs request. |
| `DELETE /v1/migrations/{}` | Remove | `src/migrations.rs:143` | `requests/migrations/` documents only `GET /v1/migrations/{uid}`. Migrations are not deleted via the REST API — they finish or are aborted via state transitions. |
| `GET /v1/migrations` | Remove | `src/migrations.rs:95` | Same — no list endpoint in docs. |
| `POST /v1/migrations` | Remove | `src/migrations.rs:107` | Same — migrations are created implicitly by `replica_of` configuration on a bdb. |
| `POST /v1/migrations/{}/pause` | Remove | `src/migrations.rs:124` | Same — no pause/resume/start verbs in docs. |
| `POST /v1/migrations/{}/resume` | Remove | `src/migrations.rs:134` | Same. |
| `POST /v1/migrations/{}/start` | Remove | `src/migrations.rs:114` | Same. |
---
## modules (`src/modules.rs`)
Docs page (`requests/modules/`) documents `GET /v1/modules` and
`GET /v1/modules/{uid}`. There is no v1 POST or PUT in the public docs, but
v2 upload IS documented elsewhere (user-defined modules, see #55).
| `DELETE /v1/modules/{}` | Verify | `src/modules.rs:156` | User-defined module management — documented in the user-defined-modules docs tree (currently being added in #55). Mark verify with cross-reference. |
| `POST /v1/modules` | Verify | `src/modules.rs:131` | Same — legacy v1 multipart upload route. |
| `POST /v2/modules` | Verify | `src/modules.rs:123` | Same — v2 multipart upload. Already covered by the in-flight user-defined-modules work. |
| `PUT /v1/modules/{}` | Verify | `src/modules.rs:162` | Same — documented under user-defined modules. |
---
## nodes subresources (`src/nodes.rs`)
Most of these are real and documented on subpages the crawler missed.
| `DELETE /v1/nodes/{}` | Verify | `src/nodes.rs:192`, `src/cluster.rs:558` | Documented at `https://redis.io/docs/latest/operate/rs/references/rest-api/requests/nodes/` as part of node lifecycle (used during `remove_node`). Inventory missed the DELETE method on the main page. |
| `GET /v1/nodes/wd_status` | Propose | `src/nodes.rs:290` | Not on the documented nodes subpages. Watchdog status is an operator-internal surface. File docs request. |
| `GET /v1/nodes/{}/alerts` | Remove | (no direct handler — appears via fixture) | Docs use **flat** path `/v1/nodes/alerts/{uid}` per `requests/nodes/alerts/`; the SDK uses the correct flat path at `src/nodes.rs:312`. The slashed shape isn't generated. Drop the fixture entry. |
| `GET /v1/nodes/{}/endpoints` | Propose | `src/endpoints.rs:109` | Mirror of `/v1/bdbs/{}/endpoints`. Not on documented subpages. File docs request. |
| `GET /v1/nodes/{}/proxies` | Propose | `src/proxies.rs:220` | Mirror of `/v1/bdbs/{}/proxies`. Not documented. File docs request. |
| `GET /v1/nodes/{}/shards` | Verify | `src/shards.rs:126` | Documented at `https://redis.io/docs/latest/operate/rs/references/rest-api/requests/shards/` — shards are queryable by node UID in the standard request shape. |
| `GET /v1/nodes/{}/stats` | Verify | `src/nodes.rs:202` | Documented at `https://redis.io/docs/latest/operate/rs/references/rest-api/requests/nodes/stats/` (GET `/v1/nodes/stats/{uid}`). The SDK shape and docs shape differ; both work live but the SDK should migrate to the flat shape. Mark verify. |
| `GET /v1/nodes/{}/stats/last` | Verify | `src/nodes.rs:202` (variant) | Documented at the same `nodes/stats/` page (last-interval shape). |
| `GET /v1/nodes/{}/wd_status` | Propose | `src/nodes.rs:301` | Same as `/v1/nodes/wd_status` — watchdog status. File docs request. |
| `POST /v1/nodes/{}/snapshots/{}` | Verify | `src/nodes.rs:270` | Documented at `https://redis.io/docs/latest/operate/rs/references/rest-api/requests/nodes/snapshots/` (snapshots page lists GET and DELETE explicitly; POST is the create flow). Note inventory may not capture POST — mark verify with note. |
---
## ocsp (`src/ocsp.rs`)
Docs page documents only `GET /v1/ocsp` and `PUT /v1/ocsp`. The SDK has more.
| `DELETE /v1/ocsp/cache` | Propose | `src/ocsp.rs:126` | Not in `requests/ocsp/` but is a legitimate OCSP cache operation. File docs request. |
| `POST /v1/ocsp/query` | Propose | `src/ocsp.rs:120` | Same — useful diagnostic verb missing from public docs. File docs request. |
(Note: `GET /v1/ocsp/status` and `POST /v1/ocsp/test` are also in the SDK but
not in the fixture — they should be checked in a future pass.)
---
## proxies (`src/proxies.rs`)
Docs page (`requests/proxies/`) explicitly lists only four endpoints and
calls out that "There are no 'stats' or 'reload' actions documented on this
proxy requests page".
| `GET /v1/proxies/{}/stats` | Propose | `src/proxies.rs:200` | Not in `requests/proxies/`. Stats per proxy is a real route on live clusters; file docs request. |
| `GET /v1/proxies/{}/stats/{}` | Propose | `src/proxies.rs:206` | Same. |
| `POST /v1/proxies/{}/actions/reload` | Propose | `src/proxies.rs:227` | Same — reload is referenced in operator runbooks but not in docs. File docs request. |
---
## redis_acls (`src/redis_acls.rs`)
| `POST /v1/redis_acls/validate` | Propose | `src/redis_acls.rs:64` | `requests/redis_acls/` documents CRUD only. The `/validate` helper is real (used by the Admin UI to pre-check ACL syntax) but not in docs. File docs request. |
---
## roles (`src/roles.rs`)
| `GET /v1/roles/{}/users` | Propose | `src/roles.rs:110` | `requests/roles/` documents standard CRUD only. The role-to-users reverse lookup is real but not in docs. File docs request. |
| `GET /v1/roles/builtin` | Propose | `src/roles.rs:105` | Same — used by the Admin UI dropdowns. File docs request. |
---
## services (`src/services.rs`)
The docs page (`requests/services/`) explicitly documents only
`GET /v1/local/services`, `POST /v1/local/services`, and `POST /v1/services`.
The rest of `ServicesHandler` (list/get/update/start/stop/restart/status) is
SDK-invented and looks like operator-internal helper code.
| `GET /v1/services` | Remove | `src/services.rs:91` | Docs do not document a list endpoint for `/v1/services`. Only `POST /v1/services` exists. Recommend `#[deprecated]`. |
| `GET /v1/services/{}` | Remove | `src/services.rs:96` | No per-service GET in docs. |
| `GET /v1/services/{}/status` | Remove | `src/services.rs:109` | No status subroute documented. |
| `POST /v1/services/{}/restart` | Remove | `src/services.rs:116` | No restart action documented. |
| `POST /v1/services/{}/start` | Remove | `src/services.rs:133` | No start action documented. |
| `POST /v1/services/{}/stop` | Remove | `src/services.rs:126` | No stop action documented. |
| `PUT /v1/services/{}` | Remove | `src/services.rs:102` | No per-service PUT documented. `PUT /v1/cluster/services_configuration` is the actual config surface for services on the cluster. |
Recommended: collapse this whole module to a single `create` method (the
documented `POST /v1/services`), or delete and route all callers to
`cluster.set_services_configuration` (which is real and documented).
---
## shards (`src/shards.rs`)
Docs page (`requests/shards/stats/`) explicitly lists
`GET /v1/shards/stats` and `GET /v1/shards/stats/{uid}`. The SDK uses a
different per-shard shape.
| `GET /v1/shards/{}/stats` | Remove | `src/shards.rs:104` | Docs use **flat** path `/v1/shards/stats/{uid}` (per `requests/shards/stats/`). The SDK already has a correct method at `/v1/shards/stats/{uid}` per the prior triage. The `/v1/shards/{uid}/stats` shape is not documented and isn't supported in `8.0.10-81` live. |
| `GET /v1/shards/{}/stats/{}` | Remove | `src/shards.rs:110` | Same — no metric-name subpath. Use the documented flat shape. |
---
## suffix / suffixes (`src/suffixes.rs`)
The docs split into two pages: `requests/suffix/` (singular, single-item GET)
and `requests/suffixes/` (plural, list GET). The SDK's `POST /v1/suffix` and
`PUT/DELETE /v1/suffix/{name}` are not in either page.
| `DELETE /v1/suffix/{}` | Propose | `src/suffixes.rs:83` | `requests/suffix/` only documents `GET`. DELETE was confirmed 404 in 8.0.10-81 live validation; this may be version-skew. File docs request and add a runtime feature gate. |
| `POST /v1/suffix` | Propose | `src/suffixes.rs:71` | Same — create not documented. |
| `PUT /v1/suffix/{}` | Propose | `src/suffixes.rs:77` | Same — update not documented. |
---
## usage_report (`src/usage_report.rs`)
Docs page documents only `GET /v1/usage_report`. Everything else in the SDK
module is invented.
| `GET /v1/usage_report/config` | Remove | `src/usage_report.rs:145` | Not in `requests/usage_report/`. |
| `GET /v1/usage_report/latest` | Remove | `src/usage_report.rs:121` | Same. |
| `GET /v1/usage_report/{}` | Remove | `src/usage_report.rs:132` | Same — usage reports are not addressable by ID; the docs treat the report as a streaming NDJSON dump. |
| `GET /v1/usage_report/{}/csv` | Remove | `src/usage_report.rs:156` | Same — no CSV variant in docs. |
| `POST /v1/usage_report/generate` | Remove | `src/usage_report.rs:139` | Same — reports are not generated on demand via this verb. |
| `PUT /v1/usage_report/config` | Remove | `src/usage_report.rs:150` | Same. |
Recommended: collapse the module to a single `get()` that streams NDJSON.
---
## users (`src/users.rs`)
Password management IS documented at `requests/users/password/` (the inventory
crawler missed the subpage). Permissions are not in the docs.
| `DELETE /v1/users/password` | Verify | `src/users.rs:252` | Documented at `https://redis.io/docs/latest/operate/rs/references/rest-api/requests/users/password/`. |
| `GET /v1/users/permissions` | Propose | `src/users.rs:225` | Not in `requests/users/`. Real route used by Admin UI. File docs request. |
| `GET /v1/users/permissions/{}` | Propose | `src/users.rs:231` | Same. |
| `POST /v1/users/password` | Verify | `src/users.rs:242` | Documented at `requests/users/password/`. |
| `PUT /v1/users/password` | Verify | `src/users.rs:247` | Same. |
---
## Per-Module Summary
| actions | 0 | 1 | 0 | Drop `DELETE /v1/actions/{}` |
| alerts | 0 | 4 | 0 | Delete top-level `/v1/alerts` handlers |
| bdb_groups | 0 | 0 | 5 | Whole module needs a public docs request |
| bdbs subresources | 4 | 6 | 3 | Major cleanup: drop actions/backup, actions/restore, actions/upgrade; fix alerts path shape; drop stale fixture lines |
| bootstrap | 4 | 0 | 1 | Update stale comment in `cluster.rs:487` |
| cluster subresources | 8 | 0 | 4 | Mostly inventory ingest; propose settings/topology/witness_disk/policy/restore_default |
| cm_settings | 0 | 1 | 0 | Drop DELETE |
| crdb_tasks/crdbs | 1 | 1 | 0 | Drop bare `POST /v1/crdb_tasks` |
| debuginfo | 0 | 5 | 0 | Whole tree should be `#[deprecated]` per docs banner |
| diagnostics | 0 | 1 | 4 | Drop POST; propose the 4 subroutes |
| endpoints | 1 | 0 | 2 | Propose bare list endpoints |
| job_scheduler | 0 | 6 | 0 | Whole per-job CRUD is fictional |
| jsonschema | 0 | 7 | 0 | Whole module beyond bare GET is fictional |
| license / migrations | 0 | 6 | 2 | Migrations is heavily fictional; propose license usage/validate |
| modules | 4 | 0 | 0 | Verify against in-flight #55 work |
| nodes subresources | 5 | 1 | 4 | Mixed |
| ocsp | 0 | 0 | 2 | Propose cache/query |
| proxies | 0 | 0 | 3 | Propose stats + reload |
| redis_acls | 0 | 0 | 1 | Propose validate |
| roles | 0 | 0 | 2 | Propose users/builtin |
| services | 0 | 7 | 0 | Module-scale cleanup; collapse to documented surface |
| shards | 0 | 2 | 0 | Path-shape mismatch; supersede |
| suffix | 0 | 0 | 3 | File docs request; gated by version skew |
| usage_report | 0 | 6 | 0 | Whole module beyond bare GET is fictional |
| users | 3 | 0 | 2 | Verify the documented password subpage; propose permissions |
---
## Top Findings (most surprising)
1. **`src/alerts.rs` exposes a top-level `/v1/alerts` resource that does not
exist in any docs version.** The handler appears alongside *correct*
scoped handlers (`/v1/cluster/alerts`, `/v1/bdbs/alerts/{uid}`,
`/v1/nodes/alerts/{uid}`), so the fix is purely removing the parallel
universe. Four routes can be deleted outright.
2. **`src/bdb.rs:800` and `src/bdb.rs:818` (`actions/backup` and
`actions/restore`) are not in the documented action enumeration at
`requests/bdbs/actions/`.** The docs page is explicit — it lists 11 action
endpoints and these two aren't among them. Source comments already flag
them as suspicious. Recommend `#[deprecated]`.
3. **`src/bdb.rs:1090` (`POST /v1/bdbs/{uid}/actions/upgrade`) is superseded
by the SDK's own `src/bdb.rs:1133` (`POST /v1/bdbs/{uid}/upgrade`).** Docs
document the bare-`/upgrade` shape at `requests/bdbs/upgrade/`. The
`actions/upgrade` variant is a duplicate at a wrong path.
4. **`src/services.rs` is mostly fictional.** The docs `requests/services/`
page documents only `POST /v1/services`, `GET /v1/local/services`, and
`POST /v1/local/services`. The SDK's GET-list, GET-by-id, PUT, status,
start, stop, restart endpoints are all SDK-invented operator helpers. The
real cluster-services config surface is `PUT /v1/cluster/services_configuration`,
which the SDK already implements separately.
5. **`src/jsonschema.rs` and `src/usage_report.rs` are mostly fictional.** Both
docs pages document a single GET endpoint and nothing else, yet the SDK
exposes specialized typed accessors and POST/PUT mutators. 13 routes total
can be deleted across these two modules.
6. **The `cluster.rs:487` source comment is wrong.** It says "Despite docs
saying /v1/bootstrap, the actual endpoint is /v1/bootstrap/create_cluster"
— but the bootstrap docs page DOES document `POST /v1/bootstrap/{action}`
with `create_cluster` and `join_cluster` as valid `{action}` values. The
inventory's apparent contradiction is just because the crawler captured
only the parameterized form. Update the comment when the handler is next
touched.
7. **The migrations module is heavily fictional.** Docs document a single
`GET /v1/migrations/{uid}` for status lookup. The SDK exposes a full
pause/resume/start/delete/create lifecycle that does not exist in the REST
API — migrations are driven by the bdb `replica_of` configuration in
reality.
8. **Stats path-shape mismatches.** Docs use a flat shape:
`/v1/bdbs/stats/{uid}`, `/v1/shards/stats/{uid}`, `/v1/nodes/stats/{uid}`,
`/v1/bdbs/alerts/{uid}`, `/v1/nodes/alerts/{uid}`. Several SDK handlers
(especially older ones in `alerts.rs` and `shards.rs`) and several fixture
lines use the inverted shape `/v1/<resource>/{uid}/stats`. Where both shapes
exist live they should be unified onto the documented flat shape; where
the slashed shape was only in the fixture (not in code), the fixture line
should just be deleted.
---
## Process Notes
- All docs URLs verified on May 26, 2026 against `latest` (currently aliasing
v7.22).
- Pages that returned 404 are flagged as **Propose** when the route is
otherwise known to work live (e.g., from existing smoke tests). These are
the strongest "real but undocumented" candidates and the best targets for an
internal docs request.
- This triage does NOT modify source code. Follow-up PRs should:
- delete or `#[deprecated]` each **Remove** entry;
- file a docs request listing all **Propose** entries (single internal
ticket, grouped by module);
- extend `scripts/export_api_inventory.py` to follow subpage links so the
**Verify** entries auto-ingest into `docs/api-inventory.csv` on the next
refresh, eliminating ~75 of the 122 false positives.