feat: 기능 추가 과정중
This commit is contained in:
@@ -0,0 +1,585 @@
|
||||
# VD-24: Runtime Schema와 boundary Mapper
|
||||
|
||||
- 상태: Accepted — reference typed codec/mapper baseline composed, artifact governance pending
|
||||
- 결정일: 2026-07-28
|
||||
- reference REST Schema/Mapper vertical: `COMPOSED`
|
||||
- semantic compatibility/codegen governance delta:
|
||||
`DESIGNED_NOT_IMPLEMENTED`
|
||||
- generated API product selection: `NOT_SELECTED`
|
||||
- 관련 결정: VD-13, VD-23, VD-25, VD-26, VD-27, VD-29, VD-30
|
||||
- 상세 설계:
|
||||
[API contract, Schema, Mapper와 Server State](../api-contract-schema-mapper-and-server-state.md)
|
||||
|
||||
## 배경
|
||||
|
||||
현재 reference vertical은 다음 trust path를 실제 실행한다.
|
||||
|
||||
```text
|
||||
HTTP response
|
||||
-> common envelope Zod
|
||||
-> feature payload Zod
|
||||
-> feature mapper
|
||||
-> domain factory
|
||||
-> application view
|
||||
-> TanStack Query
|
||||
```
|
||||
|
||||
reference baseline은 schema contribution collision을 boot 전에 거절하고,
|
||||
schema version/direction/unknown-field policy를 기록한다. request는 strict reject,
|
||||
ordinary response DTO는 strip projection을 사용하며 list item 수와 response/cache
|
||||
byte admission을 제한한다. mapper는 no-throw `MappingResult`를 반환하고 예상 가능한
|
||||
drift는 `MAPPING_CONTRACT_VIOLATION`으로 분류한다.
|
||||
|
||||
runtime schema codec과 mapper contribution은 collision-aware composer로 설치되고,
|
||||
각 REST operation의 path/request/response schema와 mapper input schema reference를
|
||||
boot 전에 exact resolve한다. operation별 cast-free result guard도 raw executor의
|
||||
성공 값을 fail-closed로 재검증한다. 남은 delta는
|
||||
actual codec fingerprint/source provenance/generated artifact join과 전체 scalar
|
||||
policy set이다.
|
||||
|
||||
이 결정은 runtime validation을 특정 library 이름으로 축소하지 않는다. 현재
|
||||
owned schema는 Zod를 사용하지만 GraphQL generated types와 protobuf messages에도
|
||||
동일한 trust transition을 적용한다.
|
||||
|
||||
## 결정
|
||||
|
||||
### 1. 다섯 validation 경계를 분리한다
|
||||
|
||||
| 경계 | owner | 목적 |
|
||||
| --- | --- | --- |
|
||||
| route/form input | presentation/feature | 사용자 입력 정규화와 UX issue |
|
||||
| application command/query input | application/feature | use-case precondition과 canonical semantic input |
|
||||
| transport request wire | adapter/contract | exact outbound representation |
|
||||
| transport response wire | adapter/contract | untrusted server bytes/message 검증 |
|
||||
| domain invariant | domain | 업무상 유효한 entity/value 생성 |
|
||||
|
||||
하나의 Zod schema를 form, API request, response와 domain에 재사용하지 않는다.
|
||||
field 이름이 같아도 trust source와 failure semantics가 다르다.
|
||||
|
||||
### 2. TypeScript와 generated type은 proof가 아니다
|
||||
|
||||
```text
|
||||
unknown bytes/message
|
||||
-> bounded decoder
|
||||
-> RuntimeCodec<ValidatedDto>
|
||||
-> ValidatedDto
|
||||
-> BoundaryMapper<ValidatedDto, ApplicationValue>
|
||||
-> MappingResult<ApplicationValue>
|
||||
```
|
||||
|
||||
`as Dto`, generic `execute<T>()`, generated TypeScript interface와 protobuf class
|
||||
instance는 runtime proof를 만들지 않는다.
|
||||
|
||||
목표 API:
|
||||
|
||||
```text
|
||||
RuntimeCodec<Input, Output>
|
||||
schemaId
|
||||
parse(input, budget) -> ValidationResult<Output>
|
||||
|
||||
BoundaryMapper<ValidatedDto, ApplicationValue>
|
||||
mapperId
|
||||
inputSchemaId
|
||||
map(dto) -> MappingResult<ApplicationValue>
|
||||
|
||||
BoundOperation<Input, Dto, Value>
|
||||
requestCodec
|
||||
responseCodec
|
||||
mapper
|
||||
```
|
||||
|
||||
operation definition 생성 시 codec output과 mapper input type을 compiler가
|
||||
연결한다. runtime registry도 same IDs/fingerprints를 검증한다.
|
||||
|
||||
### 3. Schema registry v2
|
||||
|
||||
```text
|
||||
SchemaDefinitionV2
|
||||
schemaId
|
||||
wireVersion
|
||||
boundary
|
||||
protocol
|
||||
sourceKind = OWNED | GENERATED
|
||||
sourceArtifactId
|
||||
sourceArtifactDigest
|
||||
codecId
|
||||
codecFingerprint
|
||||
unknownFieldPolicy
|
||||
numericPolicyId
|
||||
temporalPolicyId
|
||||
providerMaxEncodedBytes
|
||||
maxDecodedBytes
|
||||
maxDepth
|
||||
maxNodes
|
||||
maxObjectKeys
|
||||
maxStringBytes
|
||||
maxCollectionItems
|
||||
compatibilityPolicy
|
||||
dataClassification
|
||||
owner
|
||||
```
|
||||
|
||||
정적 metadata는 실행 codec definition에서 결정적으로 투영한다. 실제 codec
|
||||
resolver가 없는 schema ID, fingerprint가 다른 resolver와 duplicate ID는
|
||||
contribution composition에서 실패한다.
|
||||
|
||||
`codecFingerprint`는 library 내부 AST serialization을 무조건 신뢰하지 않는다.
|
||||
프로젝트가 소유한 canonical schema manifest를 사용한다.
|
||||
|
||||
```text
|
||||
canonical schema manifest
|
||||
field/path
|
||||
required/nullability
|
||||
scalar/format/range
|
||||
enum/discriminant
|
||||
collection/item ceiling
|
||||
unknown-field policy
|
||||
transform identifier/version
|
||||
```
|
||||
|
||||
Zod upgrade로 내부 representation이 바뀌어도 canonical meaning diff가 안정적이어야
|
||||
한다.
|
||||
|
||||
### 4. Decode budget
|
||||
|
||||
Content-Length나 protobuf frame length만으로 충분하지 않다.
|
||||
|
||||
```text
|
||||
ValidationBudget
|
||||
decodedBytesRemaining
|
||||
nodesRemaining
|
||||
depthRemaining
|
||||
objectKeysRemaining
|
||||
stringBytesRemaining
|
||||
collectionItemsRemaining
|
||||
deadlineRemaining
|
||||
```
|
||||
|
||||
- BFF/proxy/provider가 actual wire/encoded transfer와 decompression-ratio cap을
|
||||
집행한다.
|
||||
- browser Fetch adapter는 present/valid Content-Length를 advisory preflight로만
|
||||
사용하고 browser-visible decoded stream bytes를 hard cap으로 센다.
|
||||
- codec은 depth/node/key/string/item cap을 적용한다.
|
||||
- collection nested item도 global budget을 함께 소모한다.
|
||||
- transform/refine도 남은 logical deadline 안에서 동기적이고 bounded해야 한다.
|
||||
- async network/storage refinement를 runtime wire schema에 넣지 않는다.
|
||||
- budget 초과는 validation issue list를 무한 생성하지 않고 첫 bounded summary로
|
||||
닫는다.
|
||||
|
||||
표준 `JSON.parse` profile에서 decoded-byte cap은 pre-parse guard지만
|
||||
depth/node/key/string/item cap은 materialization 뒤 admission guard다. parse 중
|
||||
구조 cap이 필요한 payload는 bounded tokenizing parser를 별도 profile로 선택하며,
|
||||
그 구현 전에는 큰 byte ceiling을 승인하지 않는다.
|
||||
|
||||
current request `limit <= 100`은 response item ceiling이 아니다. response schema가
|
||||
items maximum과 total byte budget을 별도로 검증한다.
|
||||
|
||||
### 5. Unknown-field 정책
|
||||
|
||||
```text
|
||||
UnknownFieldPolicy
|
||||
REJECT_UNKNOWN
|
||||
STRIP_UNKNOWN
|
||||
```
|
||||
|
||||
`PRESERVE_UNKNOWN`은 application boundary에서 허용하지 않는다.
|
||||
|
||||
| schema class | 기본 정책 |
|
||||
| --- | --- |
|
||||
| request, config, command, capability | `REJECT_UNKNOWN` |
|
||||
| auth/authorization/control envelope | `REJECT_UNKNOWN` |
|
||||
| ordinary additive REST response DTO | `STRIP_UNKNOWN` |
|
||||
| GraphQL selected data object | requested field shape만 투영 |
|
||||
| sealed discriminated union | unknown discriminator 거절 |
|
||||
| protobuf generated message | codec/library unknown-field behavior 뒤 mapper는 known projection만 사용 |
|
||||
|
||||
current response `.strict()`를 모두 `.passthrough()`로 바꾸지 않는다. unknown
|
||||
field를 제거한 typed projection만 mapper로 보낸다. unknown field 이름/value를
|
||||
log에 남기지 않는다. 필요한 경우 low-cardinality `unknown-field-detected`
|
||||
observation만 sampling한다.
|
||||
|
||||
### 6. Request와 response 방향성
|
||||
|
||||
request:
|
||||
|
||||
- strict field set
|
||||
- trim/coerce/default/normalization 정책이 명시됨
|
||||
- parsed output만 transport가 serialize
|
||||
- input 원본을 query key나 request에 따로 사용하지 않음
|
||||
- route/search/application command 변환이 같은 canonical semantic input을 공유
|
||||
|
||||
response:
|
||||
|
||||
- untrusted value를 coerce하지 않음
|
||||
- required/nullability/discriminant/range를 검증
|
||||
- additive unknown은 profile에 따라 strip
|
||||
- default value를 서버가 보낸 값처럼 조용히 생성하지 않음
|
||||
- missing/null/empty를 mapper가 명시적으로 소진
|
||||
|
||||
`z.coerce`는 URL/form 같은 string input 경계에서만 허용한다. JSON/protobuf
|
||||
response에 적용하지 않는다.
|
||||
|
||||
### 7. Scalar 의미
|
||||
|
||||
#### ID
|
||||
|
||||
- opaque bounded string
|
||||
- empty/control/overlong 거절
|
||||
- 업무 계약이 없는 case folding, Unicode normalization과 numeric parse 금지
|
||||
- account/resource ID를 diagnostics label이나 physical cache key에 직접 넣지 않음
|
||||
|
||||
#### Integer와 decimal
|
||||
|
||||
- JSON integer는 finite safe integer 범위를 증명
|
||||
- `int64`/`uint64`는 JavaScript number로 mapping하지 않음
|
||||
- protobuf bigint/string representation은 adapter-private
|
||||
- money/decimal/high precision은 canonical decimal string + currency/scale policy
|
||||
- `NaN`, Infinity와 negative zero가 의미상 허용되는지 explicit
|
||||
- string-to-number response coercion 금지
|
||||
|
||||
#### Time
|
||||
|
||||
- exact RFC 3339 profile과 offset/precision을 검증
|
||||
- date-only, instant, local date-time과 duration을 다른 type으로 둠
|
||||
- leap/invalid date를 JavaScript `Date` normalization에 맡기지 않음
|
||||
- protobuf Timestamp/Duration range/nanos를 검증
|
||||
- mapper가 application temporal value로 변환
|
||||
- locale/timezone formatting은 presentation에서만 수행
|
||||
|
||||
#### Null과 absent
|
||||
|
||||
```text
|
||||
ABSENT
|
||||
NULL
|
||||
EMPTY
|
||||
VALUE
|
||||
```
|
||||
|
||||
네 의미를 schema/mapper contract에 명시한다. current mapper처럼 “string이
|
||||
아니면 모두 null”로 합치지 않는다. optional server field의 default가 필요하면
|
||||
application policy가 이름 있는 결정으로 적용한다.
|
||||
|
||||
#### Enum/union/oneof
|
||||
|
||||
- unknown discriminator는 sealed control union에서 fail-closed
|
||||
- evolvable business enum은 domain이 explicit `UNKNOWN` case와 UX를 소유한
|
||||
경우에만 mapping
|
||||
- raw unknown string/number를 domain에 전달하지 않음
|
||||
- protobuf enum zero value, unknown numeric enum과 oneof absence를 명시적으로
|
||||
처리
|
||||
|
||||
#### Binary
|
||||
|
||||
- REST base64는 decoded byte cap과 canonical encoding profile 필요
|
||||
- GraphQL upload/binary는 이 JSON schema 경계의 기본 기능이 아님
|
||||
- protobuf `bytes`는 bounded copy/stream policy 뒤에만 application으로 projection
|
||||
- large binary는 File/transfer capability를 사용
|
||||
|
||||
### 8. Transport-specific schema
|
||||
|
||||
#### REST
|
||||
|
||||
- exact status/media/envelope profile 뒤 operation DTO codec 실행
|
||||
- error body도 별도 bounded codec
|
||||
- Problem Details의 type/title/detail/instance를 raw UI copy로 사용하지 않음
|
||||
- response envelope와 payload unknown policy를 따로 설정
|
||||
|
||||
#### GraphQL
|
||||
|
||||
- variables와 selected `data` shape에 separate codec
|
||||
- top-level `data`, `errors`, `extensions`를 GraphQL response codec이 검증
|
||||
- errors path/message/extensions는 safe failure mapper 전 untrusted
|
||||
- partial policy가 허용한 missing/null만 operation DTO type에 표현
|
||||
- persisted operation manifest의 schema digest와 codec fingerprint 일치
|
||||
|
||||
#### gRPC-Web
|
||||
|
||||
- frame/trailer 검증 뒤 generated protobuf decoder 실행
|
||||
- generated decode success 뒤에도 semantic validator가 range/presence/enum/oneof를
|
||||
검증
|
||||
- descriptor digest/message full name과 codec binding 일치
|
||||
- `google.rpc.Status` details는 allowlisted type만 decode
|
||||
|
||||
#### Connect-Web/Connect
|
||||
|
||||
- Connect unary HTTP/error 또는 stream EndStream proof 뒤 generated message decode
|
||||
- JSON/binary encoding과 descriptor/message binding을 operation profile에 고정
|
||||
- generated decode와 `ConnectError` code는 semantic domain proof가 아니므로
|
||||
같은 validator/mapper와 safe failure vocabulary를 통과
|
||||
|
||||
#### Protobuf REST Gateway
|
||||
|
||||
- HttpRule/ProtoJSON/status/error profile 뒤 ordinary REST DTO codec 실행
|
||||
- generated OpenAPI type이나 ProtoJSON message를 application model로 사용하지 않음
|
||||
- direct gateway와 curated BFF의 envelope/schema를 같은 codec으로 추측하지 않음
|
||||
|
||||
### 9. Boundary Mapper v2
|
||||
|
||||
```text
|
||||
MapperDefinitionV2
|
||||
mapperId
|
||||
mapperVersion
|
||||
inputSchemaId
|
||||
outputContractId
|
||||
scalarPolicySetId
|
||||
maxOutputItems
|
||||
maxEstimatedOutputBytes
|
||||
owner
|
||||
```
|
||||
|
||||
mapper는:
|
||||
|
||||
- pure
|
||||
- deterministic
|
||||
- synchronous
|
||||
- side-effect-free
|
||||
- locale/timezone-independent
|
||||
- input mutation 없음
|
||||
- immutable output
|
||||
- exhaustive
|
||||
- bounded
|
||||
|
||||
mapper가 호출하면 안 되는 것:
|
||||
|
||||
- fetch, generated client, QueryClient
|
||||
- clock/random
|
||||
- storage/cache
|
||||
- telemetry/logger
|
||||
- DOM/browser API
|
||||
- authorization/feature flag
|
||||
|
||||
### 10. Mapping result
|
||||
|
||||
```text
|
||||
MappingResult<T>
|
||||
{ ok: true, value: T }
|
||||
{ ok: false,
|
||||
error:
|
||||
MAPPING_INVARIANT_REJECTED |
|
||||
UNSUPPORTED_WIRE_VALUE |
|
||||
OUTPUT_LIMIT_EXCEEDED }
|
||||
```
|
||||
|
||||
예상 가능한 domain invariant/unknown enum/temporal conversion 실패는 throw하지
|
||||
않는다. programming defect가 throw되더라도 adapter boundary가
|
||||
`MAPPING_CONTRACT_VIOLATION`으로 정규화한다. raw DTO/value/path/message를 failure에
|
||||
복사하지 않는다.
|
||||
|
||||
`UNKNOWN_FAILURE`는 mapper drift의 정상 분류가 아니다. operation ID,
|
||||
schema/mapper profile/version과 safe outcome만 관측한다.
|
||||
|
||||
### 11. Domain, application projection과 view
|
||||
|
||||
```text
|
||||
ValidatedDto
|
||||
-> domain value/entity factory
|
||||
-> ApplicationReadModel / command result
|
||||
-> presentation-only ViewModel
|
||||
```
|
||||
|
||||
- DTO는 adapter/contracts 내부
|
||||
- domain은 transport nullability/error/envelope를 모름
|
||||
- application read model은 query cache에 넣을 수 있는 immutable plain value
|
||||
- presentation view는 locale/formatted copy와 UI-only optimistic marker를 소유
|
||||
- domain class/service, function, native object와 generated message를 Query cache에
|
||||
넣지 않음
|
||||
|
||||
current reference가 domain을 거쳐 view를 만드는 구조는 유지한다. 단 collection과
|
||||
return object를 immutable/bounded하게 만들고 mapping type proof를 연결한다.
|
||||
|
||||
### 12. Collection mapping
|
||||
|
||||
- input array/page count는 codec에서 먼저 제한
|
||||
- mapper는 output count와 estimated bytes를 다시 제한
|
||||
- item 하나 실패 시 partial collection을 success/cache하지 않음
|
||||
- stable identity, ordering, duplicate 의미는 feature contract가 결정
|
||||
- duplicate ID를 임의로 마지막 값으로 덮지 않음
|
||||
- mapper가 sort/filter/deduplicate를 한다면 이름 있는 policy와 fixture 필요
|
||||
- pagination page/snapshot binding을 보존
|
||||
|
||||
estimated output bytes는 quota/serialization exact value가 아니라 cache admission
|
||||
ceiling용 보수적 측정이다. 측정 실패는 unlimited로 간주하지 않고 cache
|
||||
admission을 거절한다.
|
||||
|
||||
### 13. Generated와 owned source
|
||||
|
||||
```text
|
||||
backend-authoritative contract
|
||||
-> authenticated immutable source artifact
|
||||
-> source digest + provenance
|
||||
-> pinned codegen
|
||||
-> adapter-private DTO/client/codec
|
||||
-> owned semantic validator where required
|
||||
-> handwritten boundary mapper
|
||||
```
|
||||
|
||||
| protocol | generated source 후보 | 반드시 owned인 것 |
|
||||
| --- | --- | --- |
|
||||
| REST | OpenAPI DTO/client/codec | gateway, mapper, application model, query policy |
|
||||
| GraphQL | schema types, operation types | persisted manifest policy, runtime result/error codec, mapper |
|
||||
| gRPC-Web | protobuf messages/client | semantic validation, failure mapping, mapper, stream reducer |
|
||||
|
||||
normal build가 네트워크에서 최신 schema를 암묵적으로 내려받지 않는다. source
|
||||
fetch/update는 authenticated explicit workflow이며 reviewable diff를 만든다.
|
||||
|
||||
generator:
|
||||
|
||||
- exact package/plugin/runtime/Node version pin
|
||||
- reproducible output
|
||||
- generated directory 수동 수정 금지
|
||||
- clean regenerate diff 0
|
||||
- license/SBOM/secret scan
|
||||
- vendor import boundary
|
||||
- generated artifact removal gate
|
||||
|
||||
현재 `generated-api` recipe의 generic `execute<TOutput>(unknown)`와 caller-selected
|
||||
cast는 production schema proof가 아니다.
|
||||
|
||||
### 14. Compatibility
|
||||
|
||||
change classification:
|
||||
|
||||
| 변경 | 기본 판정 |
|
||||
| --- | --- |
|
||||
| optional ordinary response field 추가 + strip policy | additive |
|
||||
| request required field 추가 | breaking |
|
||||
| response required field 제거/rename/type/nullability 축소 | breaking |
|
||||
| enum value 추가 | domain unknown policy에 따라 additive 또는 breaking |
|
||||
| numeric range/precision/temporal profile 변경 | semantic breaking |
|
||||
| mapper output meaning/identity/order 변경 | application breaking |
|
||||
| unknown-field policy 변경 | compatibility review |
|
||||
| codec transform/default 변경 | semantic diff 필수 |
|
||||
|
||||
`apiContractVersion` 하나만 올리지 않는다.
|
||||
|
||||
```text
|
||||
ContractSetManifest
|
||||
globalCompatibilityVersion
|
||||
REST/OpenAPI artifact digest
|
||||
GraphQL schema + persisted operation digest
|
||||
protobuf descriptor digest
|
||||
runtime schema registry digest
|
||||
mapper registry digest
|
||||
query policy digest
|
||||
```
|
||||
|
||||
- N과 N-1 fixture를 보존
|
||||
- breaking deployment는 old frontend window와 backend compatibility를 고려
|
||||
- future major는 fail-closed
|
||||
- rollback은 frontend, generated artifacts, config, BFF/router/proxy와 backend
|
||||
compatibility를 coherent set으로 복구
|
||||
- mapper-only semantic change도 cache/release epoch invalidation을 검토
|
||||
|
||||
### 15. Failure와 cache admission
|
||||
|
||||
다음 상태에서는 cache write가 0회다.
|
||||
|
||||
- body/frame limit
|
||||
- envelope/status/media mismatch
|
||||
- operation schema mismatch
|
||||
- mapper failure
|
||||
- scope/runtime generation mismatch
|
||||
- output item/byte ceiling 초과
|
||||
- incompatible contract/source digest
|
||||
|
||||
stale data를 유지할지는 VD-25 query profile이 결정한다. schema/mapper
|
||||
incompatibility를 ordinary transient network failure와 동일하게 retry하지 않는다.
|
||||
|
||||
### 16. Security와 privacy
|
||||
|
||||
- validation failure에 raw value를 포함하지 않음
|
||||
- issue path/code를 allowlist와 count/byte cap으로 projection
|
||||
- schema/mapper error가 PII field/value를 diagnostics에 넣지 않음
|
||||
- prototype pollution key와 accessor/class/native object 거절
|
||||
- `structuredClone` 성공을 safe plain-data proof로 사용하지 않음
|
||||
- generated code가 arbitrary URL/header/logger를 application에 노출하지 않음
|
||||
- source artifact와 generator provenance 검증
|
||||
- schema가 frontend authorization boundary라는 주장 금지
|
||||
|
||||
관측 허용:
|
||||
|
||||
- operation/schema/mapper ID와 version
|
||||
- source/compatibility outcome
|
||||
- validation/mapping failure kind
|
||||
- encoded/decoded/output size와 item bucket
|
||||
- unknown-field detected bucket
|
||||
|
||||
source digest 실제 값, field path/value, DTO, GraphQL error path와 protobuf payload는
|
||||
high-cardinality/sensitive이므로 telemetry label에 넣지 않는다.
|
||||
|
||||
### 17. Testing
|
||||
|
||||
schema:
|
||||
|
||||
- missing/null/empty/unknown field
|
||||
- numeric safe bounds, decimal, negative zero, NaN/Infinity
|
||||
- RFC 3339/Timestamp/Duration edge
|
||||
- enum/union/oneof future value
|
||||
- depth/node/key/string/array/byte cap
|
||||
- invalid UTF-8, base64와 binary cap
|
||||
- N/N-1/future-major
|
||||
|
||||
registry:
|
||||
|
||||
- duplicate ID before spread
|
||||
- missing/mismatched codec/mapper resolver
|
||||
- codec fingerprint/source digest drift
|
||||
- operation schema/mapper output type binding
|
||||
- orphan/owner/version mismatch
|
||||
|
||||
mapper:
|
||||
|
||||
- typed DTO only
|
||||
- deterministic/pure/input unmodified
|
||||
- immutable output
|
||||
- no throw for expected semantic rejection
|
||||
- collection partial failure
|
||||
- item/output byte ceiling
|
||||
- missing/null/date/numeric/unknown enum matrix
|
||||
- no raw value leakage
|
||||
|
||||
codegen:
|
||||
|
||||
- source provenance/digest
|
||||
- lint/breaking
|
||||
- clean reproducible generation
|
||||
- generated import boundary
|
||||
- runtime codec fixture parity
|
||||
- dependency/removal inventory
|
||||
|
||||
integration:
|
||||
|
||||
- bytes → decoder → schema → mapper → application/query
|
||||
- schema/mapper drift에서 cache write 0
|
||||
- old runtime generation result 폐기
|
||||
- actual REST/GraphQL/gRPC provider fixture
|
||||
|
||||
### 18. Rollout
|
||||
|
||||
1. current string-dispatch schema/mapper를 그대로 두고 typed definition builder를
|
||||
추가한다.
|
||||
2. reference operation에 shadow validation/mapping을 실행하되 secondary result를
|
||||
UI/cache에 쓰지 않는다.
|
||||
3. collision-aware contribution composer와 codec fingerprint를 먼저 blocking한다.
|
||||
4. bounded decoder/collection ceiling을 query read부터 canary한다.
|
||||
5. typed mapping result와 failure taxonomy를 적용한다.
|
||||
6. current unchecked binder/cast를 제거한다.
|
||||
7. OpenAPI/GraphQL/proto generation은 제품 contract source가 선택된 것만
|
||||
별도 canary한다.
|
||||
8. schema/mapper version을 release/cache epoch와 연결한다.
|
||||
|
||||
rollback은 codec schema number를 낮추거나 cache의 incompatible value를 억지로
|
||||
decode하지 않는다. old adapter/backend path와 coherent artifact로 돌리고 current
|
||||
scope의 incompatible mapped cache를 폐기한다.
|
||||
|
||||
## 완료 기준
|
||||
|
||||
- runtime codec output과 mapper input이 compiler/runtime registry 양쪽에서 연결된다.
|
||||
- schema registry가 actual meaning fingerprint, provenance와 budget을 가진다.
|
||||
- duplicate contribution이 overwrite 전에 실패한다.
|
||||
- request strict/response additive 방향 정책이 test로 증명된다.
|
||||
- scalar/null/enum/collection 의미가 mapper policy로 닫힌다.
|
||||
- mapper가 typed DTO만 받고 expected failure를 `Result`로 반환한다.
|
||||
- generated DTO/message가 domain/application/presentation/query public type에 없다.
|
||||
- schema/mapper failure에서 cache write와 raw-data observation이 0회다.
|
||||
- N/N-1, breaking diff, provider fixture와 rollback/removal drill이 통과한다.
|
||||
Reference in New Issue
Block a user