[AZ-701] HTTP replay API service (FastAPI + magic-byte upload validation)
ci/woodpecker/push/02-build-push Pipeline failed

New replay_api component: FastAPI service wrapping the offline
gps-denied-replay pipeline. POST tlog+video (multipart) → either
sync 200 with result/map/report URLs, or async 202 + job id with
/jobs/{id} polling. Magic-byte validation, bearer auth, in-memory
JobRegistry with concurrency + queue caps (429 on overflow).

Helper accuracy_report.py promoted from tests/ to src/ because the
API needs the Markdown report writer at runtime; all AZ-699 imports
re-pointed. OpenAPI spec exported to docs.

18/18 unit tests pass (AC-1 sync, AC-2 async, AC-3 state machine,
AC-5 auth, AC-6 health, AC-8 concurrency, AC-9 magic-byte). Full
unit suite: 2251 pass, 86 skip, 1 pre-existing C12 cold-start flake
(unchanged). mypy --strict clean on the new surface.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Oleksandr Bezdieniezhnykh
2026-05-20 17:30:26 +03:00
parent b66b68ff76
commit 7d53cef0cf
22 changed files with 2854 additions and 13 deletions
@@ -0,0 +1,251 @@
openapi: 3.1.0
info:
title: gps-denied-onboard replay API
description: HTTP wrapper around the offline `gps-denied-replay` pipeline. Upload
(tlog + video [+ calibration]); receive GPS fixes + an accuracy report + an HTML
map.
version: 1.0.0
paths:
/healthz:
get:
summary: Healthz
operationId: healthz_healthz_get
responses:
'200':
description: Successful Response
content:
application/json:
schema:
additionalProperties:
type: string
type: object
title: Response Healthz Healthz Get
/readyz:
get:
summary: Readyz
operationId: readyz_readyz_get
responses:
'200':
description: Successful Response
content:
application/json:
schema: {}
/replay:
post:
summary: Post Replay
operationId: post_replay_replay_post
parameters:
- name: authorization
in: header
required: false
schema:
anyOf:
- type: string
- type: 'null'
title: Authorization
requestBody:
required: true
content:
multipart/form-data:
schema:
$ref: '#/components/schemas/Body_post_replay_replay_post'
responses:
'200':
description: Successful Response
content:
application/json:
schema: {}
'422':
description: Validation Error
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPValidationError'
/jobs/{job_id}:
get:
summary: Get Job
operationId: get_job_jobs__job_id__get
parameters:
- name: job_id
in: path
required: true
schema:
type: string
title: Job Id
- name: authorization
in: header
required: false
schema:
anyOf:
- type: string
- type: 'null'
title: Authorization
responses:
'200':
description: Successful Response
content:
application/json:
schema:
type: object
additionalProperties: true
title: Response Get Job Jobs Job Id Get
'422':
description: Validation Error
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPValidationError'
/jobs/{job_id}/result:
get:
summary: Get Result
operationId: get_result_jobs__job_id__result_get
parameters:
- name: job_id
in: path
required: true
schema:
type: string
title: Job Id
- name: authorization
in: header
required: false
schema:
anyOf:
- type: string
- type: 'null'
title: Authorization
responses:
'200':
description: Successful Response
content:
application/json:
schema: {}
'422':
description: Validation Error
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPValidationError'
/jobs/{job_id}/map:
get:
summary: Get Map
operationId: get_map_jobs__job_id__map_get
parameters:
- name: job_id
in: path
required: true
schema:
type: string
title: Job Id
- name: authorization
in: header
required: false
schema:
anyOf:
- type: string
- type: 'null'
title: Authorization
responses:
'200':
description: Successful Response
content:
application/json:
schema: {}
'422':
description: Validation Error
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPValidationError'
/jobs/{job_id}/report:
get:
summary: Get Report
operationId: get_report_jobs__job_id__report_get
parameters:
- name: job_id
in: path
required: true
schema:
type: string
title: Job Id
- name: authorization
in: header
required: false
schema:
anyOf:
- type: string
- type: 'null'
title: Authorization
responses:
'200':
description: Successful Response
content:
application/json:
schema: {}
'422':
description: Validation Error
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPValidationError'
components:
schemas:
Body_post_replay_replay_post:
properties:
tlog:
type: string
format: binary
title: Tlog
video:
type: string
format: binary
title: Video
calibration:
anyOf:
- type: string
format: binary
- type: 'null'
title: Calibration
pace:
type: string
title: Pace
default: asap
auto_trim:
type: boolean
title: Auto Trim
default: true
type: object
required:
- tlog
- video
title: Body_post_replay_replay_post
HTTPValidationError:
properties:
detail:
items:
$ref: '#/components/schemas/ValidationError'
type: array
title: Detail
type: object
title: HTTPValidationError
ValidationError:
properties:
loc:
items:
anyOf:
- type: string
- type: integer
type: array
title: Location
msg:
type: string
title: Message
type:
type: string
title: Error Type
type: object
required:
- loc
- msg
- type
title: ValidationError