Skip to content

api(ingest): /v1/ams/ingest publishes a 202 it never returns; /v1/orb/ingest omits 401/403/413 #9708

Description

@JSONbored

⚠️ Definition of Done: this issue must be completed in full, in a single PR. Do not split this
work across multiple PRs, and do not defer any Deliverable below to a follow-up issue. A PR that
satisfies only some of the Deliverables, stubs a required test, or leaves a checkbox
partially-done does NOT resolve this issue and will be closed.

Context

The two telemetry-ingest routes are near-identical handlers — the AMS one's own comment says it mirrors the ORB one ("same optional bearer-token gate, same hard body ceiling", src/api/routes.ts:4605-4607) — but their published operations disagree with the handlers and with each other.

POST /v1/ams/ingest (src/api/routes.ts:4609-4617) returns, in order: 401 unauthorized (:4610), 413 payload_too_large (:4612), 400 invalid_request (:4613), 400 on a handler error (:4615), and 200 on success (:4616). Its spec entry (src/openapi/internal-and-public-route-specs.ts:298-307) declares 202, 400, 401. The declared 202 is unreachable and the actual 200 is undeclared, and 413 is missing.

POST /v1/orb/ingest (src/api/routes.ts:4593-4603) returns 401 (:4594), 413 (:4596), 400 (:4597), 403 instance_unauthenticated (:4602), 400 (:4602), 200 (:4603). It is still a legacy registry.registerPath block (src/openapi/spec.ts:1961) declaring only 200 and 400, with no security key at all — because requiresApiToken exempts it (src/auth/route-auth.ts:77) precisely because it carries its own ORB_INGEST_TOKEN bearer. So the published document describes an unauthenticated write endpoint that cannot fail with 401.

Both are public write surfaces for third-party self-host instances, so their published contract is the only thing an integrator has.

Requirements

  • Move POST /v1/orb/ingest out of src/openapi/spec.ts:1961 and declare it as a SpecEntry in src/openapi/internal-and-public-route-specs.ts, next to the existing /v1/ams/ingest entry.
  • /v1/orb/ingest declares auth: "orb" (its bearer is ORB_INGEST_TOKEN, not a LoopOver API token), and responses 200, 400, 401, 403, 413.
  • /v1/ams/ingest's success response becomes 200 (its handler's real status). The 202 must be removed — it is unreachable.
  • /v1/ams/ingest additionally declares 413.
  • Both entries' 413 description names the body ceiling enforced by readOrbIngestBody.
  • Regenerate and commit apps/loopover-ui/public/openapi.json.

⚠️ Required pattern: mirror the existing /v1/ams/ingest entry in src/openapi/internal-and-public-route-specs.ts:298-307 (a SpecEntry with auth: "orb" and its own comment explaining the shared-secret header). It does NOT satisfy this issue to change the AMS handler to return 202 instead of correcting the spec (the 200 is the shipped, client-observed status and callers depend on it); to leave /v1/orb/ingest as a registerPath block in spec.ts and hand-add a security field; or to declare both 200 and 202 for the AMS route.

Deliverables

  • POST /v1/ams/ingest declares 200 (not 202), 400, 401, 413.
  • POST /v1/orb/ingest is declared in src/openapi/internal-and-public-route-specs.ts with auth: "orb" and responses 200, 400, 401, 403, 413; its registry.registerPath block is deleted from src/openapi/spec.ts.
  • In the regenerated apps/loopover-ui/public/openapi.json, POST /v1/orb/ingest has security: [{ "OrbBearer": [] }].
  • A new test file (e.g. test/unit/openapi-ingest-status-parity.test.ts) drives createApp() with a test env and asserts, for BOTH ingest routes, that a request with no bearer answers 401, that an oversized content-length answers 413, and that a valid authenticated batch answers 200 — and that each of those statuses is declared in buildOpenApiSpec() for that operation.
  • apps/loopover-ui/public/openapi.json regenerated and committed; test/unit/route-spec-ratchet.test.ts still passes in both directions.

All Deliverables above are required in a single PR. A PR that satisfies only some of them — for example correcting the AMS 202-to-200 without moving /v1/orb/ingest off the legacy registration, or adding the status-parity test without the spec changes — does not resolve this issue.

Test Coverage Requirements

src/api/** and src/openapi/** are inside Codecov's src/** include; the 99% branch-counted patch gate applies. The new test must exercise both arms of each ingest handler branch it touches (authorized vs not, over-ceiling vs not). The 200-vs-202 assertion is the named regression test for this fix.

Expected Outcome

Both ingest operations publish the exact status set their handlers produce, and /v1/orb/ingest publishes the bearer it actually requires. A self-host integrator generating a client from the document gets a success-status check that matches production.

Links & Resources

src/api/routes.ts:4589-4617; src/openapi/internal-and-public-route-specs.ts:298-307; src/openapi/spec.ts:1961; src/auth/route-auth.ts:77-78.

Metadata

Metadata

Assignees

No one assigned

    Labels

    gittensor:bugGittensor-scored bug fix — scores a 0.05x multiplier.help wantedExtra attention is needed

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions