582 lines
28 KiB
Markdown
582 lines
28 KiB
Markdown
# API contract와 Server State recovery
|
|
|
|
- 상태: current REST 절차 + future GraphQL/Connect/gRPC-Web/REST Gateway/
|
|
schema/cache 절차 분리
|
|
- backend 구조와 handoff:
|
|
[Backend API와 Server State contract](../architecture/backend-api-and-server-state-contract.md)
|
|
- 기준일: 2026-07-28
|
|
- 설계:
|
|
[API contract, Schema, Mapper와 Server State](../architecture/api-contract-schema-mapper-and-server-state.md)
|
|
- browser Protobuf/gateway 설계:
|
|
[Protobuf browser transport와 REST Gateway](../architecture/protobuf-browser-transport-and-rest-gateway.md)
|
|
|
|
## 1. 적용 범위
|
|
|
|
현재 reference REST → Schema → Mapper → TanStack Query vertical은 `COMPOSED`다.
|
|
하지만 다음 target delta는 아직 `DESIGNED_NOT_IMPLEMENTED`다.
|
|
|
|
- REST v2 auth fail-close/final invariant
|
|
- total logical deadline와 bounded response decoder
|
|
- complete cursor/conditional request
|
|
- typed schema/mapper registry
|
|
- strict query/mutation definition과 concurrency coordinator
|
|
- GraphQL reference adapter
|
|
- Connect-Web reference adapter
|
|
- gRPC-Web reference adapter
|
|
- Protobuf REST Gateway
|
|
|
|
GraphQL/Connect/gRPC-Web/REST Gateway 절차는 해당 runtime과 actual provider가
|
|
구현·조합된 뒤에만 운영 gate로 활성화한다. 문서나 fake fixture만으로 capability를
|
|
`AVAILABLE_NOT_COMPOSED`, `COMPOSED` 또는 production-ready라고 기록하지 않는다.
|
|
|
|
canonical readiness:
|
|
|
|
```text
|
|
Selection
|
|
TrafficAdmission
|
|
RuntimeHealth
|
|
PromotionEvidence
|
|
```
|
|
|
|
이 readiness model은 target v2 control plane이다. current v1에는 operation별
|
|
`TrafficAdmission` runtime switch가 없다.
|
|
|
|
| control | current v1 | target v2 |
|
|
| --- | --- | --- |
|
|
| operation traffic switch | 없음 | provider/family/operation별 `TrafficAdmission` |
|
|
| frontend containment | promotion 중지와 known-good release rollback; feature composition 변경은 재배포 필요 | atomic admission disable |
|
|
| provider containment | actual BFF/API owner의 route/kill switch가 있을 때만 사용 | registered provider kill switch와 probe |
|
|
| query cleanup | composed QueryClient/coordinator의 cancel·invalidate·local clear | generation fence와 profile-scoped cleanup |
|
|
| mutation recovery | backend 상태/idempotency owner와 수동 reconcile | effect certainty + runtime/scope coordinator |
|
|
|
|
따라서 current v1 incident에서 존재하지 않는 switch를 내렸다고 기록하지 않는다.
|
|
target v2가 composed된 operation만 `TrafficAdmission`을 먼저 내린다. 그 전에는
|
|
신규 promotion을 중지하고 known-good release rollback 또는 실제 backend/BFF
|
|
route 차단을 owner와 수행한다. primary status나 contract version을 운영자가
|
|
임의로 낮춰 현재 상태를 숨기지 않는다.
|
|
|
|
current v1으로의 fallback은 (1) 해당 operation의 provider/security evidence가
|
|
만료되지 않았고, (2) incident class가 v1 또는 shared boundary에 영향이 없으며,
|
|
(3) auth fail-close/final invariant hardening이 유지되는 경우만 허용한다. 하나라도
|
|
증명하지 못하면 v1을 사용하지 않고 safe unavailable 또는 실제 provider route
|
|
차단으로 닫는다.
|
|
|
|
## 2. 관측 허용과 금지
|
|
|
|
허용된 bounded aggregate:
|
|
|
|
- semantic operation/profile/provider ID
|
|
- protocol/semantics
|
|
- safe failure kind
|
|
- HTTP status group, GraphQL safe category, gRPC status bucket
|
|
- logical/physical attempt, auth recovery와 deadline bucket
|
|
- provider가 측정한 encoded transfer bucket과 browser가 측정한
|
|
decoded/result/message/frame/page/item byte/count bucket
|
|
- schema/mapper/query profile version과 compatibility outcome
|
|
- cache hit/miss/stale/refresh/admission/eviction
|
|
- mutation concurrency/optimistic/rollback/conflict/effect/invalidation outcome
|
|
- stream terminal/gap/overflow/idle bucket
|
|
|
|
금지:
|
|
|
|
- URL/path/search/header/body
|
|
- credential, cookie, CSRF, idempotency key
|
|
- GraphQL document/hash/variables/data/error message/path/extensions
|
|
- protobuf payload/debug JSON/metadata/trailer/status-details
|
|
- DTO/application/cache value/optimistic patch
|
|
- cursor/snapshot/ETag/revision/resume token
|
|
- account/tenant/resource/file ID
|
|
- raw backend request/trace/correlation value
|
|
|
|
incident ticket에 금지 값을 복사하지 않는다. credential/payload 노출 의심이면
|
|
일반 contract incident가 아니라 security incident로 분류하고 provider revoke,
|
|
key/session rotation과 로그 보존 범위를 별도 owner에게 escalate한다.
|
|
|
|
## 3. 최초 containment
|
|
|
|
1. 영향 operation family/protocol/provider/browser/release cohort를 safe aggregate로
|
|
좁힌다.
|
|
2. target v2 control이 실제 composed됐으면 해당 operation의
|
|
`TrafficAdmission`을 `DISABLED` 또는 안전한 canary cohort로 낮춘다. current
|
|
v1이면 promotion을 중지하고 known-good release rollback 또는 실제
|
|
backend/BFF route control을 사용한다.
|
|
3. query/read는 cancel하고 stream reader를 닫는다.
|
|
4. command는 무조건 retry/rollback하지 않고 effect certainty를
|
|
`NOT_APPLIED | COMMITTED | UNKNOWN`으로 분류한다.
|
|
5. `UNKNOWN` command는 backend idempotency/status/reconcile owner에게 전달한다.
|
|
6. current scope의 suspect query를 invalidate한다. wrong-scope/contract-poison
|
|
가능성이 있으면 cancel 후 current runtime cache를 clear한다.
|
|
7. GraphQL/Connect/gRPC-Web failure를 REST command로 자동 failover하지 않는다.
|
|
8. contract tuple과 artifact를 확인한다.
|
|
|
|
```text
|
|
frontend release/build
|
|
runtime config/API contract version
|
|
installed operation registry digest
|
|
runtime schema/mapper/query policy digest
|
|
REST/OpenAPI artifact
|
|
GraphQL schema + persisted manifest
|
|
protobuf descriptor/generated artifact
|
|
Connect client/server/provider profile
|
|
HttpRule/ProtoJSON/OpenAPI/gateway artifact
|
|
BFF/router/proxy/backend release
|
|
```
|
|
|
|
실제 digest 값을 high-cardinality telemetry label로 보내지 않고 incident evidence
|
|
artifact에서 access-controlled하게 비교한다.
|
|
|
|
## 4. 공통 증상 분류
|
|
|
|
| 증상 | 우선 확인 |
|
|
| --- | --- |
|
|
| 특정 release에서 전 operation 실패 | runtime config, provider endpoint, auth owner, contract set |
|
|
| schema/mapper mismatch 급증 | backend artifact rollout, unknown/null/enum/scalar 변화, wrong codec |
|
|
| retry/traffic 폭증 | retry owner 중복, 401 loop, Retry-After, total deadline |
|
|
| stale/wrong account data | scope generation, late result, query key collision, invalidation |
|
|
| command duplicate/rollback 이상 | idempotency tuple, input-aware concurrency, optimistic revision |
|
|
| list가 반복/무한 증가 | cursor loop/snapshot/page/item/byte ceiling |
|
|
| provider 200인데 client 실패 | status/media/envelope/schema/mapper/body cap |
|
|
| 로그에서 payload/ID 발견 | redaction/allowlist bypass, diagnostics producer |
|
|
|
|
## 5. Auth와 CSRF
|
|
|
|
### 5.1 Auth-required request가 무자격으로 전송됨
|
|
|
|
현재 v1은 external auth integration이 unavailable이어도 unchanged request가
|
|
전송될 수 있으므로 target v2 전까지 제품 auth-required traffic을 provider
|
|
evidence 없이 활성화하지 않는다.
|
|
|
|
target 점검:
|
|
|
|
1. session state가 authenticated인지 확인한다.
|
|
2. auth owner가 `CredentialPatch`만 반환하는지 또는 final request invariant를
|
|
재검증하는지 확인한다.
|
|
3. URL/origin/method/body digest/idempotency/conditional/CSRF가 attach 전후 같은지
|
|
확인한다.
|
|
4. unavailable/integration-failed/attach rejected에서 fetch가 0회인지 증명한다.
|
|
5. 401 recovery가 logical execution당 1회인지 확인한다.
|
|
6. concurrent 401이 single-flight recovery를 공유하는지 확인한다.
|
|
7. non-replayable command가 recovery 뒤 재실행되지 않았는지 확인한다.
|
|
|
|
의심 시 operation auth traffic을 즉시 닫는다. anonymous fallback을 만들지 않는다.
|
|
|
|
### 5.2 CSRF/CORS
|
|
|
|
1. unsafe cookie request의 exact Origin/Fetch Metadata/CSRF proof를 server에서
|
|
확인한다.
|
|
2. SameSite/custom header/preflight 하나만으로 방어했다고 기록하지 않는다.
|
|
3. cross-origin allow-origin/credentials/method/header/expose가 exact한지 확인한다.
|
|
4. wildcard credential, redirect와 unexpected origin을 복구한다.
|
|
5. CSRF token/header 값을 ticket에 기록하지 않는다.
|
|
|
|
## 6. REST incident
|
|
|
|
### 6.0 Current v1 available checks
|
|
|
|
1. current per-attempt timeout/bounded retry, Query retry off, AbortSignal과 401
|
|
recovery observation을 확인한다.
|
|
2. installed request/envelope/payload Zod schema와 mapper failure kind를 확인하되
|
|
current `Response.json()`이 body cap 증거가 아님을 기록한다.
|
|
3. QueryClient/coordinator로 affected read를 cancel/invalidate/clear한다.
|
|
4. cursor response/page runtime, APP_ETAG와 total deadline은 아직 없으므로 해당
|
|
control을 실행했다고 기록하지 않는다.
|
|
5. command effect는 backend와 reconcile한다. basic optimistic snapshot 문제가
|
|
의심되면 runtime switch를 가정하지 말고 no-optimistic/known-good release로
|
|
rollback한다.
|
|
|
|
아래 6.1~6.5는 target v2 coordinator가 해당 operation에 composed된 뒤에만
|
|
운영 절차로 활성화한다.
|
|
|
|
### 6.1 Timeout/retry storm — target v2
|
|
|
|
1. Query retry가 꺼지고 REST transport 하나만 network retry하는지 확인한다.
|
|
2. total logical deadline 안에 auth, fetch, body, mapper, recovery와 sleep이 모두
|
|
포함되는지 확인한다.
|
|
3. attempt timeout과 logical deadline exhaustion을 별도 kind로 확인한다.
|
|
4. 초회/retry/401 replay 모든 provider fetch가 하나의 monotonic
|
|
physical-attempt cap을 소비하는지 확인한다.
|
|
5. exact retry status가 network/408/429/502/503/504 중 operation subset인지
|
|
확인한다.
|
|
6. 429/503 `Retry-After`가 injected clock, max sleep/elapsed ceiling을 지키는지
|
|
확인한다.
|
|
7. timer/listener/reader leak가 있는 cohort는 traffic을 닫는다.
|
|
8. keyed command는 backend dedupe evidence 없이는 retry를 끈다.
|
|
|
|
### 6.2 Body/media/schema failure — target v2
|
|
|
|
1. final URL/status/content type을 확인한다.
|
|
2. present/valid Content-Length advisory preflight와 actual browser-visible decoded
|
|
byte cap을 확인한다.
|
|
3. actual encoded transfer/decompression ratio cap은 BFF/proxy/CDN evidence에서
|
|
확인한다. browser reader가 encoded bytes를 셌다고 가정하지 않는다.
|
|
4. standard JSON parse profile이면 decoded byte는 pre-parse guard,
|
|
depth/node/key는 post-parse admission guard인지 확인한다.
|
|
5. truncated, content encoding/decompression overflow와 invalid UTF-8을 구분한다.
|
|
6. success status/media/envelope profile이 operation registry와 일치하는지 확인한다.
|
|
7. schema unknown-field policy와 actual codec fingerprint를 확인한다.
|
|
8. failure body/value를 출력하지 않는다.
|
|
9. schema/mapper failure result를 cache하지 않았는지 확인한다.
|
|
10. backend/frontend artifact가 coherent하지 않으면 operation traffic을 닫고
|
|
N/N-1 compatible set으로 rollback한다.
|
|
|
|
### 6.3 Idempotency/ambiguous command — target v2
|
|
|
|
1. principal/operation/payload digest/key tuple과 backend TTL/status를
|
|
access-controlled evidence에서 확인한다.
|
|
2. 같은 key + 다른 payload가 거절되는지 확인한다.
|
|
3. concurrent same-key request가 duplicate commit을 만들지 않았는지 확인한다.
|
|
4. `UNKNOWN` effect에 새 key를 생성해 retry하지 않는다.
|
|
5. backend status/receipt로 `COMMITTED`면 cache reconcile/invalidate한다.
|
|
6. `NOT_APPLIED`가 증명된 경우만 정책에 따라 retry한다.
|
|
|
|
### 6.4 Cursor loop — target v2
|
|
|
|
1. query root filters/sort/scope/snapshot을 확인한다.
|
|
2. same cursor 반복, `hasMore`/cursor 모순과 non-progress page를 확인한다.
|
|
3. max pages/items/bytes를 초과했으면 추가 fetch를 중지한다.
|
|
4. snapshot이 바뀌었으면 old/new pages를 합치지 않고 root부터 재시작한다.
|
|
5. raw cursor/next URL을 로그에 남기거나 임의 follow하지 않는다.
|
|
|
|
### 6.5 Conditional request — target v2
|
|
|
|
1. operation cache owner가 `APP_ETAG`인지 browser HTTP cache인지 확인한다.
|
|
2. 304에서 exact query/scope/generation/validator binding과 mapped cached value가
|
|
모두 있는지 확인한다.
|
|
3. 304가 same query-entry cache revision CAS를 통과했는지 확인한다.
|
|
4. cached value가 없으면 304를 success로 만들지 않는다.
|
|
5. full 200 value와 validator가 atomic하게 교체됐는지 확인한다.
|
|
6. Query removal/GC, scope/logout와 release/contract/schema/mapper epoch에서
|
|
sidecar가 함께 폐기됐는지 확인한다.
|
|
7. 412 precondition과 409 business conflict를 구분한다.
|
|
8. ETag/revision 값을 incident ticket에 기록하지 않는다.
|
|
|
|
## 7. GraphQL incident
|
|
|
|
이 절은 VD-26 runtime 조합 후 적용한다.
|
|
|
|
### 7.1 Persisted operation mismatch
|
|
|
|
1. frontend schema/operation manifest와 router manifest 호환성을 확인한다.
|
|
2. operation ID, hash, schema digest와 retirement window를 artifact에서 비교한다.
|
|
3. full document fallback/APQ miss fallback을 활성화하지 않는다.
|
|
4. affected GraphQL operation traffic을 닫는다.
|
|
5. frontend + manifest + router를 coherent N/N-1 set으로 rollback한다.
|
|
|
|
### 7.2 HTTP/media + data/errors
|
|
|
|
1. selected GraphQL-over-HTTP revision, persisted-envelope extension,
|
|
`Accept`/response media와 status/body matrix를 확인한다.
|
|
2. `application/graphql-response+json`이면 허용 status에서도 body를 bounded
|
|
GraphQL envelope로 처리했는지 확인한다. legacy `application/json` non-2xx
|
|
intermediary body를 GraphQL error로 해석하지 않는다.
|
|
3. `errors=[]`, null/absent data + no errors를 envelope mismatch로 닫았는지
|
|
확인한다.
|
|
4. data/errors state branch와 operation partial policy를 확인한다.
|
|
5. raw message/path/extensions를 보지 않고 allowlisted safe code만 확인한다.
|
|
6. query partial이 `ALLOW_TYPED_PARTIAL` 조건을 모두 만족하는지 확인한다.
|
|
7. unauthorized/contract error field를 previous cache로 자동 채우지 않는다.
|
|
8. mutation이면 effect certainty/receipt를 확인한다.
|
|
9. partial/mutation error를 ordinary success로 cache하지 않는다.
|
|
|
|
### 7.3 Cost/depth/rate failure
|
|
|
|
1. persisted operation manifest의 max cost/depth/aliases/list와 router 실제 budget을
|
|
비교한다.
|
|
2. variables/response size가 frontend/server 양쪽 ceiling 안인지 확인한다.
|
|
3. client retry storm을 끈다.
|
|
4. arbitrary operation 또는 introspection을 허용해 우회하지 않는다.
|
|
5. field authorization과 cost budget을 별도 확인한다.
|
|
|
|
### 7.4 Incremental/subscription
|
|
|
|
선택된 경우에만:
|
|
|
|
- exact incremental/subscription protocol/provider revision
|
|
- exact Accept/Content-Type parameter와 payload discriminant
|
|
- multipart boundary/part/path/terminal/byte/patch count
|
|
- truncated/duplicate/out-of-order
|
|
- proxy buffering
|
|
- sequence/gap/resume/heartbeat
|
|
- bounded queue/overflow
|
|
- logout/unsubscribe
|
|
|
|
terminal completeness 전 staging을 complete query cache로 commit하지 않는다.
|
|
|
|
## 8. gRPC-Web incident
|
|
|
|
이 절은 VD-27 runtime 조합 후 적용한다.
|
|
|
|
### 8.1 HTTP success인데 RPC 실패/멈춤
|
|
|
|
1. exact client runtime/wire-spec revision/content type/transport/rpc-kind capability
|
|
matrix를 확인한다. official XHR runtime과 Connect-Web/custom Fetch runtime을
|
|
같은 cancel/deadline/frame 관측 경로로 취급하지 않는다.
|
|
2. `responseHttpStatusProfileId`와 HTTP status/gRPC media/terminal-source
|
|
교차 matrix를 확인한다.
|
|
3. custom Fetch framed runtime이면 frame prefix/length/flag/compression을
|
|
확인한다. official runtime이면 runtime-owned callback/status API와
|
|
`ClientReadableStream.cancel()` 경로를 확인하며 raw `ReadableStream` parser가
|
|
있다고 가정하지 않는다.
|
|
4. body trailer frame 또는 zero-body trailers-only response header 중 terminal
|
|
status source가 정확히 하나인지 확인한다.
|
|
5. `grpc-status`가 있으면 canonical decimal `0..16`으로 exactly once인지, body
|
|
trailer name lowercase와 rich-details outer code가 맞는지 확인하며 그 status를
|
|
authority로 사용한다.
|
|
6. `grpc-status`가 없으면 공식 fallback만 적용한다:
|
|
`400→INTERNAL`, `401→UNAUTHENTICATED`, `403→PERMISSION_DENIED`,
|
|
`404→UNIMPLEMENTED`, `429|502|503|504→UNAVAILABLE`, 그 외 `UNKNOWN`.
|
|
이것을 wire header로 위조하지 않고 internal normalized failure로만 사용한다.
|
|
7. HTTP success만으로 RPC success를 기록하지 않는다. duplicate/conflicting/
|
|
malformed terminal source는 provider incompatibility로 traffic을 닫는다.
|
|
8. Envoy의 upstream HTTP/2, filter order, route/idle/max-stream timeout과 buffering
|
|
profile을 확인한다. default route timeout으로 long stream이 잘렸는지 확인한다.
|
|
9. raw grpc-message/status-details를 ticket에 복사하지 않는다.
|
|
|
|
### 8.2 Unary response
|
|
|
|
1. OK status에서 response message가 exact 1개인지 확인한다.
|
|
2. `google.protobuf.Empty`도 zero-length payload data frame 하나여야 한다.
|
|
trailers-only OK + zero-message unary는 contract mismatch다.
|
|
3. two-or-more message/data-after-trailer/extra bytes를 contract mismatch로 닫는다.
|
|
4. generated decode 뒤 semantic schema/mapper가 통과했는지 확인한다.
|
|
5. failure/late generation에서 cache write가 0인지 확인한다.
|
|
|
|
### 8.3 Server stream
|
|
|
|
1. message/frame/total bytes/count/idle/total deadline을 확인한다.
|
|
2. bounded queue와 consumer backpressure를 확인한다.
|
|
3. duplicate/order/gap/resume token protocol을 확인한다.
|
|
4. event 전달 뒤 transport-only auto replay가 없었는지 확인한다.
|
|
5. overflow/gap/truncation에서 current aggregate를 complete success로 쓰지 않는다.
|
|
6. finite aggregate는 valid OK terminal status/completeness 뒤 atomic cache
|
|
commit인지 확인한다.
|
|
7. actual proxy buffering/flush와 affected browser cohort를 확인한다.
|
|
|
|
### 8.4 Proxy/CORS
|
|
|
|
- Envoy/BFF/selected gateway filter와 upstream route
|
|
- exact allow/expose headers
|
|
- credential/CSRF/Origin
|
|
- trailer preservation
|
|
- content type
|
|
- compression/message/deadline cap
|
|
- stream buffering
|
|
|
|
actual proxy를 복구한다. client decoder를 느슨하게 만들어 provider drift를
|
|
수용하지 않는다.
|
|
|
|
## 9. Connect와 REST Gateway incident
|
|
|
|
이 절은 VD-29/VD-30 runtime이 실제 조합된 operation에만 적용한다.
|
|
|
|
### 9.1 Connect unary/server stream
|
|
|
|
1. exact Connect-Web package/runtime, `CONNECT | GRPC_WEB`, JSON/binary,
|
|
POST/GET와 rpc kind row를 확인한다. content type으로 다른 protocol을 자동
|
|
선택하지 않는다.
|
|
2. Connect unary는 HTTP status + bounded Connect error, stream은 HTTP admission +
|
|
exactly-one final EndStream을 각각 authority로 사용한다.
|
|
3. missing/early/duplicate EndStream, terminal 뒤 data, malformed/oversize
|
|
envelope와 compression mismatch에서 call을 cancel하고 cache write를 막는다.
|
|
4. stock runtime이 whole unary body를 읽는 profile이면 edge encoded/decompressed
|
|
cap과 selected version의 actual overflow evidence를 확인한다. interceptor가
|
|
raw-byte cap을 제공했다고 기록하지 않는다.
|
|
5. remaining total deadline이 0 이하면 runtime `timeoutMs=0`을 호출하지 않고
|
|
local deadline failure로 닫는다. abort 뒤 command는 backend receipt로
|
|
reconcile한다.
|
|
6. GET은 descriptor `NO_SIDE_EFFECTS`, input classification, URL cap, cache key,
|
|
`Vary`와 credential/preflight profile이 모두 일치하는지 확인한다.
|
|
7. raw Connect message/metadata/detail/debug를 ticket에 복사하지 않는다.
|
|
|
|
### 9.2 Protobuf REST Gateway
|
|
|
|
1. selected gateway kind/version과 descriptor, canonical HttpRule manifest,
|
|
ProtoJSON profile, OpenAPI와 runtime config digest를 coherent set으로 비교한다.
|
|
2. method/path/query/body/additional binding, path escaping과 response-body
|
|
projection drift를 확인한다.
|
|
3. ProtoJSON field name/default/enum/int64/bytes/null/presence/unknown behavior를
|
|
N/N-1 fixture와 비교한다.
|
|
4. current REST envelope/status/error를 direct ProtoJSON body나 raw
|
|
`google.rpc.Status`로 잘못 decode했는지 확인한다.
|
|
5. `201/204/304/412`, ETag, idempotency, pagination과 safe error rewrite가 실제
|
|
BFF/gateway owner의 contract인지 확인한다. transcoder가 자동 제공한다고
|
|
가정하지 않는다.
|
|
6. browser abort→gateway context→upstream gRPC→application work의 cancellation/
|
|
deadline 전파를 확인한다. 이미 commit된 command는 receipt로 reconcile한다.
|
|
7. runtime response rewrite와 generated OpenAPI가 다르면 affected route admission을
|
|
닫고 coherent gateway/contract set으로 rollback한다.
|
|
|
|
Connect/gRPC-Web/REST 사이 command replay는 금지한다. read-only registered
|
|
fallback도 old generation을 cancel한 뒤 새 logical query로만 시작한다.
|
|
|
|
## 10. Schema/Mapper incident
|
|
|
|
### 10.1 Current v1 available checks
|
|
|
|
1. operation의 string schema ID가 installed Zod resolver에 있는지 확인한다.
|
|
2. envelope/payload parse와 mapper/domain factory 중 어느 current boundary에서
|
|
실패했는지 safe failure/diagnostics로 좁힌다.
|
|
3. raw DTO/value를 출력하지 않고 affected query cache write를 확인한다.
|
|
4. current registry에는 semantic fingerprint/provenance/typed mapper Result가
|
|
없으므로 이 값을 비교했다고 기록하지 않는다.
|
|
5. frontend release/runtime config/manifest의 current string contract coherence를
|
|
확인하고 known-good coherent release로 rollback한다.
|
|
|
|
### 10.2 Target v2 composed 이후
|
|
|
|
1. operation → schema ID/fingerprint → mapper ID/version binding을 확인한다.
|
|
2. source artifact/generated output/runtime codec digest를 비교한다.
|
|
3. missing/null/enum/numeric/time/unknown-field change를 classification한다.
|
|
4. request strict와 response strip/reject 방향 정책을 확인한다.
|
|
5. provider encoded-transfer와 browser decoded-byte owner를 분리하고,
|
|
item/depth/node/string admission ceiling을 확인한다.
|
|
6. mapper expected semantic failure가 throw/`UNKNOWN_FAILURE`로 소실되지 않았는지
|
|
확인한다.
|
|
7. cache write와 partial collection이 0인지 확인한다.
|
|
8. raw validation value/path/DTO를 log에 남기지 않는다.
|
|
9. incompatible schema/mapper/query cache epoch를 coherent set으로 rollback/clear한다.
|
|
|
|
## 11. Server State Cache incident
|
|
|
|
### 11.0 Current v1 available checks
|
|
|
|
1. Query retry off, global stale/gc, AbortSignal과 affected query의
|
|
cancel/invalidate/local clear를 확인한다.
|
|
2. current arbitrary key/canonicalize와 hook-local pending Promise를 관측하고
|
|
collision/incorrect join cohort cache를 clear한다.
|
|
3. current whole-snapshot optimistic rollback이 다른 commit을 덮었는지 backend
|
|
authoritative state로 reconcile한다.
|
|
4. strict key/identity token, cursor page와 optimistic layer CAS는 아직 없으므로
|
|
해당 fixture/control이 실행됐다고 기록하지 않는다.
|
|
5. 필요하면 known-good/no-optimistic release로 rollback한다. operation별 runtime
|
|
optimistic switch가 있다고 가정하지 않는다.
|
|
|
|
아래 10.1~10.4는 target v2 cache/mutation coordinator가 composed된 뒤 활성화한다.
|
|
|
|
### 11.1 Wrong/stale scope — target v2
|
|
|
|
1. VD-13 frozen scope projection과 runtime generation을 확인한다.
|
|
2. account/logout/release switch 전 query를 cancel했는지 확인한다.
|
|
3. late response/mapper/cache write fence를 확인한다.
|
|
4. raw account/resource ID를 key에서 찾거나 출력하지 않는다.
|
|
5. current runtime cache를 clear/remount하고 backend authoritative data를 refetch한다.
|
|
|
|
### 11.2 Query key collision — target v2
|
|
|
|
1. arbitrary key API가 남아 있는지 확인한다.
|
|
2. undefined/NaN/Date/class/accessor/cycle/sparse/oversize fixture를 실행한다.
|
|
3. collision 가능 cohort의 cache를 clear한다.
|
|
4. strict key codec/profile 없는 신규 query traffic을 닫는다.
|
|
5. URL/document/protobuf serialization을 key로 급히 넣지 않는다.
|
|
|
|
### 11.3 Mutation ordering/rollback — target v2
|
|
|
|
1. 전체 validated semantic input의 runtime-private exact equality + identity
|
|
token이 아닌 hook instance로 join/reject를 판정했는지 확인한다.
|
|
2. `JOIN_IDENTICAL | REJECT_DUPLICATE | ALLOW_INDEPENDENT` 결과와 fetch/Promise
|
|
횟수가 profile대로인지 확인한다.
|
|
3. runtime/scope coordinator에서 same logical key의 two-hook/out-of-order
|
|
execution을 확인한다.
|
|
4. whole snapshot rollback이 다른 committed mutation을 덮었는지 확인한다.
|
|
5. 자기 optimistic layer만 base cache revision CAS로 제거/역적용했는지 확인한다.
|
|
6. CAS miss/unknown effect에서는 다른 commit을 보존하고 invalidate/refetch한다.
|
|
7. optimistic update를 끄고 authoritative pending/refetch UX로 downgrade한다.
|
|
8. server commit 뒤 invalidation failure는 command failure로 바꾸지 않는다.
|
|
|
|
### 11.4 Cache size/pagination — target v2
|
|
|
|
1. result/page/item/estimated-byte cap을 확인한다.
|
|
2. identity intern entry/total canonical bytes/active lease와 GC/terminal release
|
|
leak를 확인한다. token/canonical bytes 자체는 출력하지 않는다.
|
|
3. unbounded collection/stream history를 cancel/evict한다.
|
|
4. binary/generated DTO를 cache value로 넣지 않았는지 확인한다.
|
|
5. max pages와 page eviction/refetch policy를 적용한다.
|
|
|
|
## 12. Rollback
|
|
|
|
target v2 coordinator가 composed된 operation:
|
|
|
|
```text
|
|
TrafficAdmission=DISABLED
|
|
-> cancel reads/streams
|
|
-> reconcile command effects
|
|
-> fence runtime generation
|
|
-> clear suspect current-scope memory cache
|
|
-> detach provider/listener/auth collaboration
|
|
-> restore coherent frontend + contract artifacts + provider/backend
|
|
-> run compatibility/provider probes
|
|
-> canary
|
|
```
|
|
|
|
current v1은 위 control이 있다고 가정하지 않는다. 신규 promotion을 중지하고
|
|
known-good release를 rollback하며, 실제 backend/BFF owner가 제공하는 route/kill
|
|
switch가 있을 때만 provider traffic을 차단한다. v1 fallback은 unexpired
|
|
provider/security evidence, incident가 v1/shared boundary 밖이라는 증거와 auth
|
|
fail-close/final invariant 유지가 모두 있을 때만 선택하고, 아니면 safe
|
|
unavailable로 닫는다.
|
|
|
|
금지:
|
|
|
|
- GraphQL/Connect/gRPC command를 REST 또는 gateway route로 자동 replay
|
|
- schema number/digest만 낮추기
|
|
- incompatible cache value를 cast/loose parse
|
|
- validation/mapper를 끄고 traffic 유지
|
|
- unknown command effect를 optimistic rollback만으로 해결
|
|
- auth unavailable을 anonymous request로 downgrade
|
|
|
|
## 13. Security containment
|
|
|
|
다음은 security owner에게 즉시 escalate한다.
|
|
|
|
- credential/CSRF/idempotency/presigned material이 cache/log에 노출
|
|
- auth owner가 endpoint/method/body를 변경
|
|
- unauthorized request가 실제 전송
|
|
- GraphQL arbitrary document/field authorization bypass
|
|
- gRPC metadata/status details payload 노출
|
|
- cross-account cache observation
|
|
|
|
신규 traffic을 닫고 credential/session/provider key/manifest를 필요한 scope에서
|
|
revoke/rotate한다. 삭제/보존은 incident response 정책을 따른다.
|
|
|
|
## 14. Drill과 evidence
|
|
|
|
분기 또는 major contract 변경 전:
|
|
|
|
- REST auth unavailable/final-request mutation
|
|
- total deadline/retry/401 single-flight
|
|
- oversized/truncated/schema/mapper
|
|
- idempotency concurrent replay/unknown effect
|
|
- cursor loop/ETag 304/412
|
|
- GraphQL persisted miss/partial/cost
|
|
- gRPC missing/conflicting terminal status source, corrupt frame와 stream gap
|
|
- query key collision/account late result
|
|
- optimistic concurrent rollback
|
|
- kill switch/coherent rollback
|
|
- GraphQL/Connect/gRPC/Gateway generated dependency/provider removal
|
|
|
|
evidence record:
|
|
|
|
```text
|
|
protocol/operation/provider/profile
|
|
frontend/backend/router/proxy/browser version
|
|
contract artifact compatibility outcome
|
|
fault/drill ID
|
|
safe result
|
|
started/completed timestamp
|
|
owner/reviewer
|
|
artifact retention/expiry
|
|
```
|
|
|
|
raw payload, URL, document, protobuf와 identifier를 evidence record에 넣지 않는다.
|
|
|
|
## 15. 관련 문서
|
|
|
|
- [VD-23 API transport selection과 REST execution](../architecture/decisions/VD-23-api-transport-selection-and-rest-execution.md)
|
|
- [VD-24 Runtime Schema와 boundary Mapper](../architecture/decisions/VD-24-runtime-schema-and-boundary-mapper.md)
|
|
- [VD-25 Server State Cache lifecycle](../architecture/decisions/VD-25-server-state-cache-lifecycle.md)
|
|
- [VD-26 Persisted GraphQL operation](../architecture/decisions/VD-26-persisted-graphql-operation.md)
|
|
- [VD-27 gRPC-Web unary와 server stream](../architecture/decisions/VD-27-grpc-web-unary-and-server-stream.md)
|
|
- [VD-29 Connect-Web와 browser Protobuf runtime](../architecture/decisions/VD-29-connect-web-and-browser-protobuf-runtime.md)
|
|
- [VD-30 Protobuf contract와 REST Gateway](../architecture/decisions/VD-30-protobuf-contract-and-rest-gateway.md)
|
|
- [VD-13 Client cache scope와 persistence](../architecture/decisions/VD-13-client-cache-scope-and-persistence.md)
|