Skip to content

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:

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:

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.