# VD-23: API transport selection과 REST execution - 상태: Accepted — REST v2 security/execution baseline composed, advanced profiles pending - 결정일: 2026-07-28 - installed REST reference vertical: `COMPOSED` - REST v2 security/execution baseline: `COMPOSED` - provider/path/auth profile baseline: `COMPOSED` - conditional execution/provider-conformance delta: `DESIGNED_NOT_IMPLEMENTED` - GraphQL/Connect/gRPC-Web/REST Gateway product selection: `NOT_SELECTED` - 관련 결정: VD-13, VD-24, VD-25, VD-26, VD-27, VD-29, VD-30 - 상세 설계: [API contract, Schema, Mapper와 Server State](../api-contract-schema-mapper-and-server-state.md) - browser Protobuf/gateway 설계: [Protobuf browser transport와 REST Gateway](../protobuf-browser-transport-and-rest-gateway.md) ## 배경 현재 reference feature는 operation registry, request Zod schema, shared HTTP executor, response envelope/payload schema, mapper, gateway, application input과 TanStack Query까지 실제 production composition에 연결된다. 따라서 REST 경로 자체를 미구현으로 표시하지 않는다. 현재 reference operation은 v2 metadata, collision-aware composition, allowlisted credential patch, auth fail-before-fetch, prefix-preserving target, shared logical deadline, exact JSON media/success status, bounded decoder와 typed mapping failure를 실행한다. correlation header, success status group과 401 replay를 포함한 physical attempt도 terminal observation에 연결한다. operation은 path placeholder↔codec key exact join, named provider/bearer/CSRF profile, provider credential-mode ceiling과 encoded query byte ceiling도 실행한다. 남은 production delta는 cookie-CSRF/CORS evidence, 204/304/412 conditional transaction, artifact digest와 실제 provider conformance다. `API_CONTRACT_VERSION` 문자열 일치만 backend compatibility 증거로 사용하지 않는다. ## 결정 ### 1. Protocol 선택은 operation registry가 소유한다 feature application port는 protocol-neutral이다. ```text feature use case -> feature gateway -> exact semantic operation -> REST adapter -> persisted GraphQL adapter -> Connect adapter -> gRPC-Web adapter ``` - 한 `operationId`는 한 protocol에만 binding한다. - UI, query hook과 use case는 protocol을 선택하지 않는다. - URL, GraphQL document, service/method와 generated request를 application input으로 받지 않는다. - 같은 command를 provider failure 때문에 다른 protocol로 자동 replay하지 않는다. - read fallback도 동일 auth/freshness/schema/mapper/query identity와 하나의 total retry budget을 증명한 registered policy만 허용한다. - GraphQL/Connect/gRPC-Web adapter를 공통 `HttpClient`의 mode flag로 넣지 않는다. 공통으로 공유하는 것은 execution context, auth collaboration, failure vocabulary와 observation뿐이다. ### 2. REST operation은 실행 source와 정적 manifest를 분리하지 않는다 목표 API는 feature가 generic이 연결된 definition을 만든다. ```text defineRestOperation< Path, Search, Body, SuccessWire, SuccessValue, Failure >({ common, providerId, method, uriTemplate, pathCodec, searchCodec, bodyCodec, successCodec, errorCodec, mapper, policies }) ``` 실행 definition에서 registry manifest를 결정적으로 투영한다. schema metadata, 실제 codec map, operation-specific TypeScript map과 mapper를 서로 다른 string dispatch table에 수기로 중복하지 않는다. manifest 최소 field: ```text protocol = REST registryVersion providerId operationId owner semantics method relativePathTemplate pathSchemaId searchSchemaId bodySchemaId requestMediaProfile successStatusProfiles[] errorStatusProfiles[] responseSchemaId mapperId authProfileId csrfProfileId replayPolicy idempotencyKeyPolicy deadlineProfileId retryProfileId paginationProfileId | null conditionalProfileId serverStateProfileId | null maxRequestBytes maxDecodedResponseBytes maxResponseItems observabilityProfileId compatibility ``` ### 3. Contribution composer는 collision 전에 실패한다 ```text feature contributions[] -> preserve every source row -> validate contribution owner/version -> detect duplicate operation/schema/mapper/query/topic ID -> resolve every codec/mapper/profile reference -> validate semantic coherence -> freeze installed registry -> emit compatibility manifest ``` object spread의 last-write-wins를 금지한다. duplicate ID가 payload까지 동일해도 owner를 하나 선택하지 않고 build를 실패시킨다. alias/rename은 versioned migration row로만 허용한다. semantic coherence: - `GET`/`HEAD`는 body 없음, `SAFE`만 허용 - `HEAD`는 body success codec 없음 - `POST`/`PATCH` retry는 `IDEMPOTENT | KEYED_COMMAND` 또는 명시적 `SAFE` semantics 필요 - `KEYED_COMMAND`는 `idempotencyKeyPolicy=REQUIRED`, 다른 replay policy의 key attach/금지는 exact key profile과 일치 - `NON_REPLAYABLE`은 retry와 401 replay 금지 - success/error status가 겹치지 않음 - 204 profile은 body/schema 없음 - 304는 query + conditional profile + existing cache binding 필요 - 412는 precondition profile 필요 - path placeholder 집합과 path codec key 집합이 exact match - query/cache profile은 `QUERY` operation에만 연결 - mutation invalidation은 registered topic만 사용 ### 4. Provider endpoint와 URI application은 provider URL을 받지 않는다. ```text RestProviderProfile providerId baseOrigin basePathPrefix allowedCredentialsModes corsProfile referrerPolicy redirectPolicy = ERROR defaultHeaders allowedResponseOrigins ``` - non-local은 HTTPS만 허용한다. - provider는 credential mode ceiling만 제공하고 operation의 auth transport profile이 exact mode를 선택한다. anonymous는 `omit`, same-origin cookie는 approved `same-origin`, approved cross-origin cookie만 `include`다. - base URL의 username, password, query와 fragment를 금지한다. - exact origin과 canonical base path prefix를 보존한다. - operation template은 relative API path이며 scheme, authority, query와 fragment를 포함하지 않는다. - leading slash가 base prefix를 제거하는 `new URL()` ambiguity를 쓰지 않는다. - encoded slash, dot segment, NUL/control, duplicate slash와 overlong path를 정책대로 거절한다. - redirect는 기본 `error`다. 로그인/다운로드 handoff는 일반 JSON REST operation과 다른 capability다. path parameter: - path codec의 parsed output만 encode한다. - missing, extra, empty와 length 초과 parameter를 network 전에 거절한다. - Unicode normalization을 업무 ID에 임의 적용하지 않는다. - path value와 최종 URL은 diagnostics에 기록하지 않는다. query: - key ordering, repeated-array/comma style, boolean, null/absent/empty semantics를 profile에 고정한다. - URL encoded byte ceiling을 적용한다. - raw `URLSearchParams`, query string과 next URL을 caller에게 받지 않는다. - sensitive/private value를 GET query에 넣는 operation은 별도 security review가 없으면 금지한다. ### 5. Request projection과 final invariant request는 다음 소유 순서로 만든다. ```text operation + validated input -> immutable request binding -> body canonical serialization + digest -> transport-owned headers/options -> constrained auth/CSRF patch -> final invariant validation -> fetch ``` transport-owned header: - `Accept`, `Content-Type` - contract/media version - bounded correlation/trace context - idempotency key - conditional validator - approved CSRF header caller와 feature mapper가 arbitrary header를 추가하지 않는다. auth owner target: ```text CredentialPatch credentialMode allowlisted header name/value proof expiry/generation ``` operation auth profile은 final Fetch `credentials`를 exact하게 고정한다. `ANONYMOUS | BEARER_HEADER`는 ambient cookie가 섞이지 않게 `omit`, same-origin cookie session은 `same-origin`, cross-origin cookie는 별도 CORS/CSRF provider evidence가 있는 profile만 `include`다. provider ceiling과 맞지 않으면 fetch 0회다. auth owner가 `Request` 전체를 반환하지 않는다. transition 기간에 current port를 사용한다면 attach 전후의 다음 값이 exact하게 같아야 한다. - URL/origin/path/query - method - body digest - content type/length - correlation, idempotency, conditional와 CSRF binding - redirect/cache/referrer/credentials/mode 다르면 `AUTH_INTEGRATION_FAILURE`, fetch 0회다. auth-required operation은 session state가 `authenticated`가 아니면 fetch하지 않는다. `integration-failed`, `unauthenticated`와 credential attach rejection을 anonymous request로 downgrade하지 않는다. ### 6. Cookie auth, CSRF와 CORS same-origin BFF cookie session을 기본 권장한다. - cookie는 Secure/HttpOnly이며 provider가 SameSite 정책을 소유한다. - unsafe method는 server의 exact Origin/Fetch Metadata 검증과 composition-issued anti-CSRF proof를 요구한다. - CSRF proof는 application/query/cache에 노출하거나 persistence하지 않는다. - custom content type/preflight가 있다는 사실만 CSRF 방어로 간주하지 않는다. cross-origin profile은 다음을 actual provider에서 증명한다. - exact `Access-Control-Allow-Origin`, wildcard 금지 - credentials mode와 allow-credentials 일치 - exact allow-method/allow-header - 필요한 request ID, ETag, Retry-After만 expose - OPTIONS와 actual response의 policy 동등성 - redirect 없음 ### 7. Replay와 idempotency ```text ReplayPolicy SAFE IDEMPOTENT KEYED_COMMAND NON_REPLAYABLE ``` - `SAFE`: read-only이며 network/recovery retry 가능 - `IDEMPOTENT`: 같은 principal/operation/payload/precondition의 반복 request가 의도한 server effect를 추가로 만들지 않으며 duplicate response/status mapping을 backend contract가 명시한다. response byte가 항상 동일하다는 뜻은 아니다. - `KEYED_COMMAND`: application logical command lease가 key를 생성하고 lifecycle 전체에서 유지 - `NON_REPLAYABLE`: ambiguous result에서 자동 재실행 금지 `KEYED_COMMAND` binding: ```text principal scope operation ID/version canonical payload digest idempotency key server retention/expiry ``` backend는 atomic claim, concurrent same-key join/replay, same-key different-payload rejection과 terminal receipt를 제공한다. header를 보냈다는 사실만 replay safety가 아니다. provider conformance가 없으면 retry/401 recovery traffic을 켜지 않는다. current client가 execute 호출마다 key를 생성하는 방식은 network attempt 안에서는 재사용되지만 ambiguous terminal 뒤 사용자 retry와 연결되지 않는다. 목표 command owner가 effect certainty를 다음처럼 반환한다. ```text NOT_APPLIED | COMMITTED | UNKNOWN ``` `UNKNOWN`은 새 key 자동 retry가 아니라 status/reconcile 또는 명시적 사용자 복구로 닫는다. ### 8. Logical deadline, cancel과 retry ```text LogicalExecutionBudget totalDeadlineMs attemptTimeoutMs maxAttempts maxCumulativeSleepMs maxRetryAfterMs authRecoveryCount = 0 | 1 ``` total deadline은 다음 모두를 포함한다. - operation/schema lookup과 request encode - credential/CSRF attachment - fetch attempt - body read/decode/schema/mapper - 401 recovery - retry backoff/Retry-After 각 phase는 남은 total budget보다 긴 timer를 만들지 않는다. timer, abort listener, response reader와 auth waiter는 모든 terminal path에서 정리한다. 초회, network/status retry와 401 recovery replay를 포함한 **모든 API provider fetch**는 하나의 monotonic `physicalAttemptCount`를 증가시키고 `maxAttempts`를 소비한다. `authRecoveryCount`는 추가 상한일 뿐 attempt counter, sleep budget이나 total deadline을 reset하거나 우회하지 않는다. retry status는 operation의 exact subset만 허용한다. ```text network failure 408 429 502 503 504 ``` - 429와 503의 `Retry-After`를 injected clock으로 parse한다. - hard ceiling을 넘는 Retry-After는 sleep하지 않고 terminal로 닫는다. - full jitter와 attempt/sleep/elapsed 세 상한을 모두 적용한다. - schema, mapper, 4xx validation/authz/conflict와 redirect failure는 retry하지 않는다. - caller cancel, navigation supersede, runtime teardown, attempt timeout과 logical deadline을 다른 safe failure로 유지한다. - 401 recovery는 auth-required이면서 replay-safe한 operation만 한 번 수행한다. - 동시 401은 session owner의 single-flight recovery를 공유한다. - physical attempt, logical retry와 auth replay를 따로 관측한다. ### 9. Closed execution public executor는 promise rejection 대신 항상 closed result로 끝난다. ```text RestExecutionResult SUCCESS VALIDATION_REJECTED AUTH_REQUIRED | AUTH_INTEGRATION_FAILURE REQUEST_ABORTED REQUEST_ATTEMPT_TIMEOUT | REQUEST_DEADLINE_EXCEEDED NETWORK_UNREACHABLE RATE_LIMITED | SERVER_FAILURE HTTP_FAILURE CONTENT_TYPE_MISMATCH | BODY_LIMIT_EXCEEDED | MALFORMED_BODY SCHEMA_MISMATCH | MAPPING_CONTRACT_VIOLATION PRECONDITION_FAILED | CONFLICT CONTRACT_INCOMPATIBLE ``` attempt timer와 전체 logical deadline은 error registry, safe user copy와 telemetry bucket에서도 별도 closed kind로 유지한다. 둘 다 raw URL/timing detail을 노출하지 않는다. operation lookup, URL construction, `Headers`, body serialization, `Request`, auth collaboration, fetch, read, parse, schema와 mapper를 모두 catch/normalize 경계 안에 둔다. thrown value/body/header/URL을 failure에 복사하지 않는다. ### 10. Response admission과 bounded decoder body를 `Response.json()`으로 바로 읽지 않는다. ```text response -> final URL/status/header admission -> exact media type parser -> present/valid Content-Length advisory preflight -> bounded stream reader -> actual browser-visible decoded byte count -> UTF-8/profile decoder -> JSON structural ceiling -> envelope/status codec -> operation response codec -> mapper ``` browser Fetch의 `Response.body`는 일반적으로 content decoding 뒤 stream이므로 client가 actual wire/encoded byte를 신뢰성 있게 세었다고 주장하지 않는다. - BFF/proxy/CDN가 encoded transfer와 decompression ratio ceiling을 집행한다. - browser client는 present/valid `Content-Length`를 advisory rejection에만 쓰고 actual decoded bytes를 hard cap으로 센다. - 표준 `JSON.parse` profile은 decoded-byte cap이 pre-parse resource guard이고 depth/node/key/string/item cap은 materialization 뒤 admission guard다. - 구조 cap을 parse 중 강제해야 하는 더 큰 profile은 bounded tokenizing JSON parser를 별도로 선택하고 actual browser evidence를 가져야 한다. cap 초과, truncation과 invalid UTF-8에서 reader를 cancel하고 cache에 쓰지 않는다. media parser는 type/subtype/parameter를 exact하게 해석한다. - `application/json` - approved vendor `application/*+json` - RFC Problem Details profile - explicit 204 no-content `includes("application/json")` 검사는 목표 계약이 아니다. 각 success status는 response codec을 가진다. 현재 envelope는 `REST_ENVELOPE_V1` profile로 유지할 수 있지만 모든 REST provider에 강제하지 않는다. success status와 error body가 모순되면 status/profile 계약 실패다. ### 11. Error projection backend error는 먼저 status/media별 codec을 통과한다. - raw message, stack, body와 arbitrary extensions를 버린다. - code/category는 operation error profile의 allowlist로 mapping한다. - unknown backend code는 closed generic failure다. - validation issue는 최대 count, path/code byte/charset와 allowed path를 제한한다. - request ID, trace ID와 correlation ID도 length/charset cap을 적용한다. - `retryable` backend boolean을 client retry authority로 사용하지 않는다. - 401/403/404 existence-hiding은 provider/product policy를 따른다. - 409 business conflict와 412 representation precondition failure를 분리한다. ### 12. Cursor pagination ```text CursorPageWire items nextCursor | null hasMore snapshotToken | null ``` response codec은 item count, item size, cursor/snapshot byte와 total decoded ceiling을 검증한다. mapper는 immutable `CursorPage`을 만든다. - cursor는 opaque이며 decode/로그/telemetry 금지 - arbitrary next URL을 따라가지 않음 - filters/sort/scope/snapshot과 cursor를 exact binding - same cursor 반복, `hasMore=true`인데 cursor 없음, non-progress loop 거절 - maximum pages/items/cache bytes 이후 fetch 중지 - TanStack infinite query의 root key에는 semantic filter만 넣고 cursor는 bounded `pageParam`으로 관리 - offset pagination은 stable small dataset이 증명된 별도 profile만 허용 current reference list array는 complete pagination 구현이 아니다. ### 13. Conditional read와 optimistic concurrency operation별 owner: ```text ConditionalProfile NO_STORE APP_ETAG BROWSER_HTTP_CACHE APPLICATION_REVISION ``` 모든 operation은 한 profile을 가져야 한다. - `NO_STORE`, `APP_ETAG`, `APPLICATION_REVISION`은 Fetch `cache=no-store`. - `BROWSER_HTTP_CACHE`만 exact browser cache mode와 server `Cache-Control`/`Vary` contract를 사용한다. - caller/library default에 맡기는 implicit `NONE`은 없다. `APP_ETAG`: - strong ETag/generation은 adapter-private metadata - exact operation/query/scope/representation binding과 함께 memory에 보존 - `If-None-Match`를 transport가 생성 - 304는 same binding의 mapped cached value가 있을 때만 freshness 갱신 - 304는 same query-entry cache revision CAS가 성공할 때만 commit - cached value가 없으면 one-time unconditional request 또는 closed failure - app-managed conditional operation은 fetch cache mode를 `no-store`로 고정 - full 200 mapped commit과 validator install/update는 같은 entry transaction - query removal/GC, scope/logout, release/contract/schema/mapper epoch reset에서 validator sidecar도 함께 폐기 - ordinary invalidation에서 validator 보존 여부는 profile이 고정 `BROWSER_HTTP_CACHE`: - standard browser cache가 revalidation을 소유 - application이 hidden validator/304 logic을 중복 구현하지 않음 - HTTP `Cache-Control`을 TanStack `staleTime`으로 자동 변환하지 않음 write precondition: - exact resource revision을 `If-Match` 또는 body contract로 binding - 412는 `PRECONDITION_FAILED` - current server representation을 refetch한 뒤 feature use case가 overwrite, merge 또는 cancel을 결정 - 409 business conflict와 합치지 않음 ETag/revision은 authorization proof가 아니며 raw value를 diagnostics에 넣지 않는다. ### 14. Schema와 Mapper 연결 VD-24의 typed codec/mapper를 사용한다. ```text unknown -> RuntimeCodec -> Mapper -> Result ``` request는 strict/normalized parsed output만 serialize한다. ordinary additive response는 required/discriminant를 검증하고 unknown field를 폐기한다. control, authorization와 sealed union은 unknown을 거절한다. generated OpenAPI client/DTO를 선택해도 adapter-private이다. handwritten gateway와 mapper를 제거하지 않는다. ### 15. Query cache와의 관계 REST transport는 raw response cache를 소유하지 않는다. VD-25가 mapped application projection을 TanStack Query에 admission한다. - operation registry의 cache profile만 query를 만들 수 있다. - Query retry는 `false`; REST transport가 network retry를 소유한다. - URL, ETag, idempotency key, Response와 DTO를 query key/value에 넣지 않는다. - mutation success 뒤 registered invalidation topic 또는 exact typed seed policy만 사용한다. - REST timeout/error를 Query가 다시 network retry하지 않는다. ### 16. Contract source와 release coherence OpenAPI가 backend authority인 제품: ```text authenticated immutable OpenAPI artifact -> source digest/provenance -> lint + breaking diff -> pinned deterministic generation -> runtime codec parity -> adapter-private DTO/client -> handwritten mapper/gateway ``` CI: - generator/runtime/plugin/Node version pin - clean checkout regenerate diff 0 - stable operation ID - source/artifact/generated output digest - runtime codec vs specification fixtures - N/N-1 and future-major failure - generated import boundary global `API_CONTRACT_VERSION`은 selected contract-set compatibility와 digest에 연결한다. runtime config와 release manifest의 같은 문자열만으로 backend compatibility를 주장하지 않는다. major version 전략은 URI version 또는 vendor media version 중 provider가 하나를 선택한다. 동시에 둘을 임의 증가시키지 않는다. v1/v2 adapters는 같은 application gateway를 구현할 수 있지만 같은 query entry에 representation을 섞지 않는다. ### 17. Security와 observability 관측 허용: - semantic operation/provider/profile ID - method/semantics - outcome/AppFailure kind/HTTP status group - logical retry, auth recovery와 physical attempt bucket - duration/deadline/request-response byte/item bucket - conditional/cache outcome 금지: - URL, path/search/header/body - cursor/snapshot/ETag/revision - idempotency/CSRF/auth token - raw backend code/message/request/trace value - application resource/account/tenant ID client correlation ID는 bounded syntax로 request에 전달하고 server-projected request/trace ID는 safe failure/observation에만 제한한다. 한 logical execution은 terminal event 하나를 만든다. ### 18. Composition과 readiness REST v2 composition owner가 다음을 atomic하게 만든다. ```text parse provider/config -> compose collision-free operation registry -> resolve codec/mapper/policy references -> install auth/CSRF owner -> run compatibility/provider probes -> publish READY facade ``` partial registry/client를 application에 노출하지 않는다. ```text Selection TrafficAdmission RuntimeHealth PromotionEvidence ``` primary status가 `COMPOSED`여도 provider/auth/CSRF/idempotency/conditional conformance가 없으면 `TrafficAdmission=DISABLED`와 `PromotionEvidence=MISSING | PARTIAL | EXPIRED`로 닫는다. kill switch: - provider 전체 - operation family - keyed retry/401 replay - conditional request - optimistic mutation - query cache admission ### 19. Test와 provider conformance deterministic: - contribution collision, missing codec/mapper/profile와 owner mismatch - URI template/path/query canonicalization/base-prefix preservation - method/body/replay/status/media coherence - anonymous/cookie/bearer credentials와 Fetch cache mode matrix - auth final-request mutation 공격과 unavailable auth fetch 0 - attempt timeout vs total deadline, timer/listener/reader cleanup - concurrent 401 single-flight - 401 replay를 포함한 monotonic physical-attempt cap - retry matrix, injected-clock 429/503 Retry-After - same key/same payload replay와 same key/different payload rejection - 204/304/412/422/problem/envelope - oversized/truncated/malformed/decompression overflow - cursor loop/snapshot/page ceiling - ETag 304 without cache, If-Match 412 - mapper failure와 redaction actual staging provider: - HTTPS/base path/CORS/preflight/credential - cookie/Origin/CSRF - idempotency concurrent claim/TTL/reconcile - status/media/error codec - cursor/snapshot/conditional semantics - rate limit/Retry-After - correlation/request/trace projection - proxy/CDN content encoding and body cap - browser decoded-byte cap과 provider encoded/decompression ceiling - outbound correlation, success status group와 401 physical-attempt observation MSW 통과는 provider conformance가 아니다. ### 20. Rollout 1. collision-aware v2 registry/codec과 boot-time binding 검증을 설치한다. 2. auth fail-closed, final invariant, bounded decoder와 total deadline을 local reference vertical에서 검증한다. 3. actual provider에 같은 fixture를 실행하고 read operation을 canary한다. 4. keyed command는 backend idempotency conformance 뒤 별도 canary한다. 5. pagination/conditional operation을 각각 별도 traffic gate로 올린다. 6. provider/browser/operations evidence가 complete인 operation만 enabled한다. 7. rollback은 우선 safe unavailable로 내리고 contract artifact/frontend/backend를 coherent set으로 복구한다. v1 fallback은 해당 operation의 unexpired provider/security evidence가 있고 incident가 v1/shared boundary에 영향이 없으며 auth fail-close/final invariant hardening이 유지될 때만 허용한다. ### 21. Removal GraphQL/Connect/gRPC-Web/REST Gateway 선택을 취소해도 REST v2 common execution context는 남을 수 있다. REST provider 제거 시: 1. 신규 operation admission 중지 2. read cancel, command effect certainty reconcile 3. auth/CSRF/retry timer와 response reader close 4. current scope query cache clear/invalidate 5. operation/schema/mapper/query profile 제거 6. provider config/proxy/dependency/fixture 제거 7. production module inventory와 backend route retirement evidence ## 완료 기준 - installed REST operation이 typed path/search/body/success/error codec과 mapper에 하나의 definition으로 연결된다. - auth unavailable 또는 mutated final request에서 fetch가 0회다. - 모든 throw/response size/status/media/schema/mapper failure가 closed result다. - total logical deadline이 auth/recovery/backoff/decode/mapper를 포함한다. - replay는 declared policy와 actual backend idempotency evidence를 가진다. - complete cursor page와 conditional/412 state가 bounded하게 동작한다. - response DTO/URL/header/token/validator가 application/query/log에 없다. - actual provider conformance와 rollback/removal drill이 통과한다.