--- kind: CONCEPT slug: application-core-c10 title: 임의 Object 대신 sealed 변수 대수를 쓴 이유 topic: schema-and-wire-models project: clean-architecture-backend-template status: 게시 전 sourceRevision: 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916 rootTreeNode: concept:application-core-c10 evidenceCapturedOn: 2026-09-01 assets: - key: application-core-c10 file: ../../../final/evidence/rendered/application-core-c10.svg - key: application-core-c10-diagram file: ../../../final/assets/diagrams/application-core-c10.svg evidence: - ../../../final/evidence/raw/application-core-c10.txt source: - 원본 분석 절은 final/document.md#a03#L230 이다. module: application-core --- # 임의 Object 대신 sealed 변수 대수를 쓴 이유 가변·임의 변수가 serialization/fingerprint drift와 `toString` 충돌을 만들 수 있었던 것이 변경 근거이고, 그 뒤로 비밀 경계가 계약 바깥에 따로 서 있다. ## 관계 - **legacy storage/notification compatibility surface의 제거 조건 추적** 같은 분석 리프에서 끌어낸 규칙이다. ## 본문 public contract는 arbitrary `Object`/`Map`를 허용하지 않고 sealed `NotificationVariable` algebra를 사용한다. 과거 mutable/arbitrary variable 때문에 serialization/fingerprint drift와 `toString` collision이 가능했던 것이 변경 근거다. ## 공개 계약과 비밀이 나뉘는 자리 :::evidence key="application-core-c10-diagram" alt="sealed 변수 대수와 고정된 템플릿 판본과 유계 수신자 수가 공개 알림 계약 안에 놓이고 임의 Object 변수와 연락처 원문이 바깥에 빗금으로 놓인다" caption="공개 계약과 비밀이 나뉘는 자리" zoom="false" ::: ## 이 기록이 다루는 범위 :::evidence key="application-core-c10" alt="코드베이스에서 파일 목록을 만든 출력 25줄. 이 기록이 다루는 범위가 그 목록이다." caption="코드베이스 파일 목록 — 25줄 · exit 0" zoom="true" ::: ## vacuous pass가 남긴 regression guard structural test는 public API에 arbitrary Object가 다시 들어오지 않는지 검사하며, 과거 잘못된 test root로 vacuous pass했던 문제도 regression guard로 남아 있다. `NotificationPlan`은 exact template version을 pin한다. recipient/metadata/variable count/depth가 bounded되어 있고, receipt는 "durable logical acceptance"이지 provider delivery를 의미하지 않는다. ## decrypt 실패를 빈 값으로 떨어뜨리지 않는다 contact point는 encrypted value + keyed fingerprint로 분리되고 protected contact rendering은 원문을 노출하지 않는다. template variable 자체에 reset token 같은 secret이 들어갈 수 있어 payload protection이 존재한다. contact lookup/provider request/callback fingerprint는 HMAC purpose를 분리해 동일 secret-purpose reuse를 피한다.