Files
AutopilotMonitor/src
Oliver Kieselbach bca53bd43d refactor(v2core): M4.4.2 backend telemetry uploader HTTP skeleton
Concrete IBackendTelemetryUploader implementation for the Plan §2.7a
POST /api/telemetry/batch endpoint. Skeleton only — the live backend
endpoint lands in M5; this milestone only needs the client-side contract
testable against HttpMessageHandler fakes.

Design:
- New class BackendTelemetryUploader in Transport/Telemetry/ (NOT added as a
  method on the M2-copied Legacy BackendApiClient, which is slated for
  removal in M4.5 / v11.1+). Lives next to IBackendTelemetryUploader;
  clean layer, no legacy cross-dependency.
- HttpClient injected (not self-constructed). mTLS client-cert wiring stays
  with the orchestrator-builder in M4.4.5 via
  HttpClientHandler.ClientCertificates; the uploader itself is cert-agnostic,
  which makes it trivially testable with a custom handler.
- Ctor deps are flat: baseUrl, tenantId, optional hardware/bootstrap/version
  headers. No AgentConfiguration coupling — orchestrator extracts values.
- No retry/back-off here; TelemetryUploadOrchestrator (M4.1) owns that.
- Body: JSON array of TelemetryItem via Newtonsoft (PascalCase; Kind as
  string via existing StringEnumConverter annotation). No gzip — evaluate
  in M5 once bandwidth profile is known.
- HTTP status -> UploadResult mapping:
    2xx                 -> Ok
    401 / 403           -> Permanent ("unauthorized: ...")
    408 / 429           -> Transient (rate limit / request timeout)
    other 4xx           -> Permanent (client bug; retry pointless)
    5xx                 -> Transient
    HttpRequestException-> Transient ("network: ...")
    TaskCanceledException (HttpClient internal timeout, not caller CTS)
                        -> Transient ("timeout: ...")
    OperationCanceledException with caller-CTS signaled -> rethrow
  Empty batch short-circuits with Ok (no HTTP call) to avoid wasted
  round-trips when a concurrent drain emptied the spool mid-upload.
- Security headers: X-Tenant-Id (pre-body auth check), hardware headers
  (X-Device-Manufacturer/Model/SerialNumber for whitelist + Autopilot
  validation), optional X-Bootstrap-Token (pre-MDM OOBE), X-Agent-Version
  for kill-switch + diagnostics.

New Constants.ApiEndpoints.TelemetryBatch = "/api/telemetry/batch" — shared
with M5 backend-side routing.

+26 tests (1313 -> 1339 green): URL + header shape, JSON body wire-format
(Kind as string, TelemetryItemId/PK/RK/PayloadJson round-trip), empty-batch
short-circuit, full HTTP status-code -> UploadResult matrix (2xx/401/403/
4xx/408/429/5xx), HttpRequestException + timeout mapping, caller
cancellation propagation, null-arg rejection.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 18:54:07 +02:00
..