# Raw Gin Surface Classification

> Canonical path: `specs/api/raw-gin-surface-classification.md`
> Status: living classification policy
> Related spec: [`specs/api/internal-api-clean-code-design.md`](./internal-api-clean-code-design.md), [`specs/api/handler-adapter.md`](./handler-adapter.md)
> Live inventory tool: `guardrails/api/internal-api-clean-code-design.sh`

## Purpose

This spec defines how raw `*gin.Context` handlers in `internal/api` are
classified. It is not a frozen inventory of current package counts.

The current raw Gin count and package distribution come from
`guardrails/api/internal-api-clean-code-design.sh`. Do not encode generated
counts in this document as durable truth. If a cleanup slice relies on a point
in time inventory, include the guardrail output in the implementation handoff or
review notes instead.

## Live Inventory Procedure

Run the API guardrail from the repository root:

```bash
guardrails/api/internal-api-clean-code-design.sh
```

Use the `Raw Gin handler inventory by package` section as the live source for
which packages currently contain raw Gin functions. For every nonzero package,
review the handlers and classify them by the categories below.

Update this spec only when the classification categories, allowed reasons, or
review procedure changes. When code changes add, remove, or migrate handlers,
the guardrail output should change automatically; the canonical docs should not
need a count-only edit.

## Classification Categories

| Category | Meaning |
|----------|---------|
| `keep-raw` | The handler intentionally remains raw Gin because the protocol does not fit the standard typed adapters. |
| `migrate-now` | The handler is a safe typed-adapter migration candidate with no known behavior-preservation blocker. |
| `migrate-later` | The handler can move to typed adapters after a missing adapter feature or unresolved preservation detail is designed. |
| `remove` | The handler is dead code or superseded by another route. |

## Keep Raw By Design

Product handlers do not keep raw Gin by default. New and migrated handlers use
typed requests plus adapters, including binary/media reads through the typed
seekable-content response. Raw Gin is restricted to the adapter/context
infrastructure that implements those typed abstractions.

The following legacy protocol surfaces remain migration debt only while the
corresponding typed primitive is missing:

1. Public/auth flows with unauthenticated state, cookies, redirects, refresh
   token bodies, or OAuth callback requirements.
2. Machine/API-key/internal daemon protocol flows.
3. Multipart upload, proxy, and legacy avatar/sticker/attachment flows not yet
   migrated. Binary download alone is no longer a reason to remain raw:
   `api.Content` preserves content type, headers, conditional requests, and
   byte ranges through `http.ServeContent`.
4. Webhook and external provider callback entry points.
5. Optional-body routes whose auth, redirect, cookie, or pre-body validation
   order cannot be represented by the standard typed adapter without wire drift.
6. Realtime, WebSocket, Socket.IO, or other streaming upgrade paths.
7. Root adapter toolkit functions that implement typed request/response
   infrastructure rather than exposing product routes.

`internal/api/raw_gin_handler_guardrail_test.go` parses production Go files
with the Go AST and requires the current raw-handler set to exactly equal
`internal/api/testdata/raw_gin_handler_baseline.txt`. The equality is
intentional: adding a raw handler fails, and migrating one requires deleting
its baseline entry, preventing that method from being resurrected later.

## Migration Rules

Migrate a raw handler opportunistically when all of the following are true:

- The route is an authenticated browser API, workspace-scoped browser API, or
  ordinary internal API that does not need protocol-specific Gin control.
- The body is ordinary JSON, or a legacy empty-or-JSON contract that can be
  represented by a domain-local wrapper backed by `api.BindEmptyOrJSON`.
- Route parameters, auth/workspace preconditions, invalid JSON messages, status
  codes, and response bodies can be preserved.
- The owning domain package can cover route parity and wire behavior with
  focused tests.

Do not migrate raw Gin merely to reduce a generated count when doing so makes
the route adapter more obscure or moves protocol-specific behavior into a
generic wrapper.

## Required Evidence

For any API cleanup slice that changes raw Gin usage:

- Run `guardrails/api/internal-api-clean-code-design.sh` before and after the
  change and compare the raw Gin inventory.
- Document the classification for newly retained raw handlers in the package,
  related domain spec, or implementation handoff.
- Add or update focused route/wire tests when a handler migrates to a typed
  adapter.
- Keep `specs/api/internal-api-clean-code-design.md` and
  `specs/api/handler-adapter.md` as the durable architecture and adapter
  contracts.
