Skip to content

Storage Media Parity Smoke

Scope

This opt-in smoke supports P3-002 by comparing a real legacy media asset read with the native document-service read path. It is read-only: it fetches legacy metadata/content, fetches native content, compares byte hashes, and writes artifacts for review.

The smoke does not change the default gateway route table and does not create, update, or delete media assets.

Modes

  • STORAGE_PARITY_NATIVE_MODE=asset-id: compare legacy /api/storage/media-assets/{id}/content with native /v1/storage/media-assets/{id}/content.
  • STORAGE_PARITY_NATIVE_MODE=storage-key: read the legacy detail payload, extract storageKey, and compare original legacy content with native /v1/storage/objects/content?storageKey=.... This helps prove object-store byte parity before native media metadata backfill exists.
  • STORAGE_PARITY_NATIVE_MODE=gateway: compare legacy direct content with gateway /api/storage/media-assets/{id}/content while the gateway uses deploy/gateway/routes.storage-native-localhost-example.json.
  • STORAGE_PARITY_NATIVE_MODE=auto: try native asset-id content first, then fall back to storage-key for the original variant.

Required Runtime

Start these processes before live mode:

  • legacy API, default LEGACY_API_BASE_URL=http://localhost:4001
  • document-service, default DOCUMENT_BASE_URL=http://localhost:8097
  • optional API gateway, default GATEWAY_BASE_URL=http://localhost:8085
  • shared object storage reachable by both legacy and native services

For gateway mode, start the gateway with:

bash
GATEWAY_ROUTE_TABLE=deploy/gateway/routes.storage-native-localhost-example.json

Compose route-table proof uses the sibling table:

bash
GATEWAY_ROUTE_TABLE=deploy/gateway/routes.storage-native-example.json

That Compose-facing v2 table is strict: it does not contain a broad /api fallback and does not expose the legacy single-PUT presigned write route.

Run

Static self-test:

bash
cd go-platform
STORAGE_PARITY_SELF_TEST=1 make test-storage-media-parity

Live original-byte parity:

bash
cd go-platform
STORAGE_PARITY_MEDIA_ASSET_ID=<legacy-media-asset-id> \
STORAGE_PARITY_AUTHORIZATION='Bearer <token>' \
STORAGE_PARITY_ORGANIZATION_ID=<org-id> \
STORAGE_PARITY_NATIVE_MODE=auto \
make test-storage-media-parity

Live image variant parity when native media metadata exists:

bash
STORAGE_PARITY_MEDIA_ASSET_ID=<image-media-asset-id> \
STORAGE_PARITY_AUTHORIZATION='Bearer <token>' \
STORAGE_PARITY_ORGANIZATION_ID=<org-id> \
STORAGE_PARITY_NATIVE_MODE=asset-id \
STORAGE_PARITY_VARIANTS=original,trim,formula \
make test-storage-media-parity

Assertions

The smoke fails unless:

  • legacy media detail returns 2xx
  • each requested legacy content variant returns 2xx
  • the matching native content path returns 2xx
  • SHA-256 hashes match for each compared variant
  • in gateway mode, the native response includes X-Hoctapaz-Gateway-Route: storage

Artifacts are written under output/storage-media-parity-* by default and include raw response bodies, headers, media summary, and parity-report.json.

Browser Proof Gate

This smoke proves HTTP/media byte parity; it is not browser UI proof by itself. Before public storage route promotion, the owning slice must add a named browser smoke that opens a real import/question/document page through the frontend, loads media through the gateway, and verifies browser-observed storage route headers plus rendered media artifacts.

Minimum browser proof:

  • frontend started with API calls pointed at api-gateway
  • gateway started with the matching non-default storage route table
  • document-service and shared object storage reachable
  • browser observes the expected X-Hoctapaz-Gateway-Route for a storage read
  • rendered image/document content is non-empty and matches the media asset or storage-key fixture under test
  • artifacts are written under output/playwright/

Rollback

Switch GATEWAY_ROUTE_TABLE back to deploy/gateway/routes.json, remove the native storage route entry, or set it to legacy_proxy. This smoke does not mutate runtime data.

Go-platform documentation is generated from repository Markdown.