# OpenAPI parity and validation

The pinned Immich 3.2.2 source declares 276 operations across 192 paths and
41 domains. The source bytes are retained in `api-spec/immich.openapi.json` with
SHA256 `7db8383741eeb5c5c8c87a6221cd1cdd1206c8b1190b83363c64223a00bb020b`.
The complete method inventory is 123 GET, 66 POST, 42 PUT, 43 DELETE and 2 PATCH.

## Current candidate and historical measurements

The current candidate is generated by builder PR21 revision
`16aec3838c5908021a9a735ce62e8d6eaa3e83f6`, landed unchanged in merge
`32df4821d1272d804e22ace5880bb1b43d4a2f24`.
It preserves the independently reviewed provider sidecar, all 276 operations and
native bounded search discovery. Canonical repairs extract origin and confirmation
helpers, preserve multipart semantics, and send checker diagnostics to stderr.
The complete catalog uses compact JSON: 4,581,458 bytes, with unchanged content.
Actual native schema freshness now passes. The refactored measurement runner
passed all 276 API and 276 native proxy operations in 195.63 seconds, producing
552 mock requests and zero provider calls. The affected behavior suite passed
224 tests in 44.02 seconds. The unchanged sanitizer accepts the complete catalog
and detects a synthetic secret in a separate negative-control copy; its 8 MiB
limit and all security rules remain intact. Stdout and Ruff hooks pass.
The current dispatch receipt is
`validation/full-operation-parity-16aec38-2026-10-13.json`.
The development dependency pin is now landed SDK
`04a68087dbd3867bbb20e6ce286ffdd654028183`. The preceding builder `8ae60277`
candidate, landed unchanged in `f0d8adef`, passed 752 exhaustive tests
in 212.29 seconds, including all 276 API and 276 native proxy operations, plus
confirmation and denial controls. The exact source hashes and scope are recorded
in `validation/exhaustive-native-proxy-2026-10-13.json`. The normal pre-commit run
found complexity, schema scan-size, CLI stdout and immutable-input formatting
blockers. Fresh checks verify the generator repairs and measurement refactor;
no generated or handwritten consumer function fails complexity. The operator
approved a narrow exception for the immutable upstream evidence, conditional on
preserving the existing pipeline `main` references. Only `auth.service.ts` and
`misc.ts` are omitted from the staged complexity inventory. The adapter imports
the shared hook's scanner and per-file comparison without changing thresholds.
Only the exact raw OpenAPI and upstream LICENSE paths are omitted from the EOF
fixer. Before either commit or push, the adapter verifies all four index and
working-tree byte hashes. Security scanning remains unchanged, and all connector
code stays in scope. Scope regressions reject changed bytes, missing index files,
symlink replacements and broader filename matches. Final normal gates and
publication remain pending.

The separately approved clone policy admits only the 14 exact paths and hashes
in `.config/generated-schema-policy.json`: the generated inventory, the diagnosed
provenance/validation records, and the unchanged upstream `auth.service.ts`.
The canonical wrapper scans complete Git-tree snapshots and removes a pair only
when both members are verified artifacts. Every implementation-to-artifact and
implementation-to-implementation pair remains. Historical trees without the
manifest receive no exclusions. The verifier binds compiler/runtime provenance,
regenerates the inventory twice, compares exact bytes, and checks the native MCP
schemas without provider calls. It also verifies all evidence hashes and rejects
any file or mode change during verification. This policy changes no scanner
thresholds, source bytes, security checks, or pipeline `main` references.

One separately reviewed security false positive is adjudicated before history
scan deduplication: line 63 of the pinned maintenance-worker service is a public
upstream mock value. The adapter requires the exact path, regular-file Git mode,
Git blob, SHA-256 and literal. Every other added line goes to the shared detector
unchanged, including other credentials in the same file and unknown historical
blobs. Plain-text scanning, scanner self-checks and entropy reporting retain the
shared behavior. Raw upstream files remain byte-identical.
The following measurements belong to the earlier generator and SDK overlay;
they do not validate the current tree or published PR head. The fresh source-only
environment still does not establish full lock installation or live acceptance.

All 276 operations passed through both API and actual native MCP dispatch under
protocol `2026-07-28` in 64.09 seconds on FastMCP 4.1.0. The run produced
552 mock HTTP requests, 153 distinct write confirmations and no remaining
operation failures. Eight confirmation controls passed in 8.99 seconds on 4.1.0.
The earlier 4.0.11 run also passed all 276 operations on both surfaces, plus
194 controls in 12.92 seconds covering operator write refusal, invalid and
denied confirmation, multipart handling and single-attempt HTTP errors.

That run's generator revision was `f8a1ded81b8565d048cacaaa10831964fd1b4a47`.
SDK base `6b35633add03580a209bb8db7796b11a8994f2c5` was combined with the
owner's uncommitted overlay, SHA256
`14b906063f7032c2a1d15c40e78c6084018f9caf8faf6c975c260dd2e803003e`.
The repository's `validation/full-operation-parity-fastmcp-4.1.0-2026-10-12.json`
records source hashes and every operation outcome. Those historical receipts
remain unchanged. The current development lock was regenerated for the landed
SDK without builds or installs; it is resolution evidence, not an installed
dependency-closure result. The earlier consumer test retained
EG Python source `d33abec1`, also pinned by the current consumer lock; the SDK's
own bootstrap pins the distinct source `f17f47ab`. The hash-verified
FastMCP wheels were isolated over the existing test environment. These results
do not establish a complete lock installation or released dependency closure.

## What the checks establish

The generated inventory records every source operation, its effective security
declaration and vendor extensions. The packaged canonical compiler checks that
the contract retains every operation and its exact method, route, parameter and
response schemas. Native discovery initially lists only `search_tools` and
`call_tool`. Exact searches retrieve each complete domain schema and compare it
with the contract, including FastMCP's actual reference expansion. The additional
album metadata tool is also measured against the same disclosure budget.

`tests/test_operation_parity.py` then calls each operation through the real API
client and an actual native MCP client through FastMCP's `call_tool` proxy.
HTTPX's mock transport is the only
provider boundary replacement. The mock checks request method, path, query,
headers and JSON, form or multipart body; the test checks the complete typed
response. Successful operation IDs must cover the source exactly, with no
missing, extra or duplicate entries.

MCP writes must complete the SDK confirmation flow under protocol `2026-07-28`.
The tests do not replace the confirmation helper or select a legacy protocol.
Every write is also checked with operator write mode disabled. Explicit denial
must produce no HTTP request, and 403, 429 and 503 errors must produce only one
HTTP attempt for each declared method. These requests use synthetic fixtures
and an `.invalid` origin. They do not mutate or certify the live provider.

Run the tests in the approved environment containing the repository's declared
dependencies:

```bash
python -m pytest tests/test_operation_parity.py -q
python scripts/generate_tool_schemas.py --check
python scripts/generate_immich_content.py --check
```

The normal pre-push hook runs the complete test suite. Source dependencies and
scanner revisions must accompany any reported validation result; a collection
count or successful tool listing is not dispatch evidence.

## Authorization evidence and readiness

Seventeen source operations omit both operation and root `security` declarations.
The canonical inventory retains these raw omissions. Independently reviewed
classifications bind each operation, method, route and operation hash to 13 files
at the pinned provider commit. The reviewed sidecar digest is
`43f936578e5361b4400750ccb9e04747948eabe19baad0e78d90774c9c79c432`.
The receipt is `validation/provider-evidence-review-2026-10-13.json`.
Verification rereads both sidecar and source files; a cached contract receipt is
insufficient. To inspect this source evidence without claiming operational readiness:

```bash
python -m immich_api.parity.check_openapi_parity \
  api-spec/immich.openapi.json immich_api --inspect \
  --provider-overlay api-spec/immich.provider-evidence.json \
  --expected-overlay-sha256 43f936578e5361b4400750ccb9e04747948eabe19baad0e78d90774c9c79c432 \
  --evidence-root api-spec/provider-source
```

Provider source at commit `60b51cb3bc909e72fe963f4dfb1947515cb9ab3b` explicitly
marks the 17 routes public at the normal account authentication guard. This does
not mean each operation is unrestricted. Password login still checks a password;
admin signup and restore initialization require setup to be available; OAuth
callback and logout require their respective proofs; maintenance login requires
a valid maintenance token while maintenance mode is active. Public maintenance
status reveals additional detail only for a valid token. The guard checks setup
before admitting a public route. The source review retains these preconditions
and does not change runtime authorization or enable writes.

## Provider export differences

The served schema and Immich's checked-in SDK schema are not byte-identical.
Replaying the provider's `patchOpenAPI` export transforms produces exact object
equality with its checked-in 3.2.2 schema. The transforms sort required fields and
parameters, remove three `propertyNames` entries and one binary `contentEncoding`
entry for OpenAPI 3.0 compatibility, and convert `x-immich-required` on
`AssetMediaCreateDto.assetData` into a standard required field.

The connector preserves the served source bytes and constraints. The reviewed
sidecar makes only the additive `assetData` required-field correction; it removes
no constraints and changes no operation or security objects. The effective source
SHA256 is `4733e4346a7c22cfdac9eb9cbb5298f42662c8b3f5b3cc450cfd2d4347e60e77`.
The equivalence
check is provenance evidence, not permission to discard validation constraints.
The upload fixture includes the required asset file. The no-file multipart
regression covers only the backup upload whose source schema permits that shape;
it establishes serialization, not successful live backup processing.

Unicode property patterns are translated into literal ranges from pinned Unicode
18 data matching the reviewed `regex` runtime. Positive and negative examples and
all code points in the supported letter, mark and number categories are checked.
Unsupported property syntax fails rather than losing its constraint. This records
the converter's Unicode semantics; it does not claim a deployed Node runtime's
Unicode version.

The earlier eager catalog measured about 4.6 MB. The current server supports
`IMMICH_API_MCP_CLIENT_BUDGET`, an operator-provided JSON file path specifying
a named client, discovery mode, and input/output/tool/listing/search byte limits.
With `regex-search`, the entire underlying catalog remains available while each
search returns at most one complete schema. Oversized schemas fail explicitly;
constraints are never truncated. No budget is inferred from the generated size.

`tests/fixtures/native-client-budget.json` defines a synthetic FastMCP 4.1.0 test
client with 1 MiB schema/tool/search limits and a 16 KiB initial listing limit.
The exhaustive suite configures this through the ordinary server setting and
checks initial disclosure, all 41 domain schemas, the album sample schema, and
every operation through the proxy. These limits are test inputs, not approval for
any production model. An operator must supply a supported production client
budget and run native admission with that same runtime configuration before
operational readiness can be assessed.

Live endpoint checks, credential scope, source-built images, fleet composition and
graph receipt/readback remain separate acceptance work.
