refactor(managementapi): carry the resolved namespace on the context (S23 Step 4)

What

S23 Step 4 of the usage-data foundation plan: slugMiddleware now carries a narrow projection of the resolved namespace row (resolvedNamespace: UUID, slug, and the entity_type/entity_id fields of the ADR-007 anchor tuple) on the request context instead of only the UUID. Handlers read it through the typed accessors requestNamespace/requestNamespaceID.

Behavior-preserving: the five route handlers keep calling requestNamespaceID unchanged, and every pre-existing resolution path (existence-hiding 404, contract-violation 500, short-circuit on failure) is untouched.

Why

The S23 first event (Step 5) needs the namespace slug and anchor tuple at emission time. The middleware already fetches the full row via FindBySlug and then discarded everything but the UUID; this seam exposes what is already read, so the emitting handler needs no second namespace fetch.

Design choices

  • Narrow struct over the raw jet row: handlers stay off the datastore model. Platform is omitted because no consumer reads it.
  • namespaceIDFromContext dropped: after the rewire it had no production callers (requestNamespaceID reads through requestNamespace).

Spec coverage

Spec: docs/specs/S23-usage-data-collection.md. This step is the seam the spec's Design section requires ("the resolution seams expose the anchor-tuple fields they already read"). Step acceptance maps to:

  • Accessor exposes slug and anchor tuple: TestSlugMiddleware_InjectsResolvedNamespace, TestRequestNamespace_ReturnsResolvedNamespace
  • Behavior preserved: TestSlugMiddleware_InjectsNamespaceID, TestSlugMiddleware_ShortCircuitsOnFailure, TestSlugMiddleware_NilNamespaceWithoutError_Writes500 (rewritten through the middleware), TestRequestNamespaceID_ReadsResolvedNamespace, TestAccessors_MissingNamespace_Write500, plus the untouched handler suites in internal/managementapi

Acceptance criteria

# Criterion Tests
AC-1 Disabled/omitted section: Track and lifecycle succeed, no HTTP Owned by Step 2 (!912 (merged)). Not tested in this MR.
AC-2 Valid config: collector POST cx carries both context schemas Owned by Step 2 (!912 (merged)). Not tested in this MR.
AC-3 ar_instance_version equals app.Version, not settable via Attrs Owned by Step 2 (!912 (merged)). Not tested in this MR.
AC-4 correlation_id equals the request's correlation ID Owned by Step 2 (!912 (merged)). Not tested in this MR.
AC-5 Out-of-enum RepositoryKind/UpstreamType drops + counter Owned by Step 2 (!912 (merged)). Not tested in this MR.
AC-6 Forced gitlab_standard validation failure drops via same path Owned by Step 2 (!912 (merged)). Not tested in this MR.
AC-7 Shutdown drains queued events; bounded when unreachable Owned by Step 2 (!912 (merged)). Not tested in this MR.
AC-8 Track race-safe under concurrent use Owned by Step 2 (!912 (merged)). Not tested in this MR.
AC-9 Successful create emits one event with first-event dims; none on failure Owned by Step 5. This MR lands the seam it consumes: TestSlugMiddleware_InjectsResolvedNamespace, TestRequestNamespace_ReturnsResolvedNamespace.
AC-10 Emitter metrics under service prefix; dropped counter registered Owned by Steps 2-3. Not tested in this MR.

Error cases

# Condition Tests
E-1 Invalid usage_data config: load fails, service refuses start Owned by Step 1 (merged, internal/config/usagedata_test.go). Not tested in this MR.
E-2 Collector unreachable: retry/backoff, 10k queue, overflow drop LabKit-owned emitter behavior; surfaced via Steps 2-3 metrics. Not tested in this MR.
E-3 Context validation failure: drop + counter + log Owned by Step 2 (!912 (merged)). Not tested in this MR.
E-4 Track after Shutdown: no-op, reason="stopped" Owned by Step 2 (!912 (merged)). Not tested in this MR.
E-5 Process exit with queued events: lost Accepted loss per ADR-012; no test by design.

Security considerations

# Concern Tests
S-1 No tokens, credentials, or raw PII in payloads Owned by Steps 2 and 5. Not tested in this MR.
S-2 Props limited to ADR-012 catalog dimensions Runtime key allow-list, owned by Step 2 (!912 (merged)). Not tested in this MR.
S-3 Attrs cannot carry version, correlation ID, or identity Owned by Step 2 (!912 (merged)). Not tested in this MR.
S-4 TLS enforced for the collector outside development Owned by Step 1 (merged, internal/config/usagedata_test.go). Not tested in this MR.
S-5 enabled = false: nothing leaves the process Owned by Step 2 (!912 (merged)). Not tested in this MR.

Merge request reports

Loading
Loading