Summary#
research_status 같은 enum 기반 상태값은 curation pipeline에서 정규화(normalization) 경계, 알 수 없는 값 처리, 실패 경로의 관측 가능성을 명확히 설계해야 한다. 특히 unknown, ?, null, 미정의 문자열, 신규 enum 값이 섞이면 파이프라인이 조용히 skip 하거나 동일 항목을 반복 재처리하는 failure mode가 생긴다.
권장 패턴은 다음과 같다.
- 외부 입력 enum은 내부 상태 enum으로 즉시 정규화한다.
- 알 수 없는 값은 정상 상태처럼 통과시키지 말고
UNKNOWN_EXTERNAL_STATUS또는INVALID_STATUS같은 별도 내부 sentinel로 분리한다. - 상태 전이 실패는 silent skip 하지 않고 structured log, metric, audit event를 남긴다.
- 재처리 가능한 실패와 데이터 계약 위반 실패를 구분한다.
- 반복 실패 항목은 dead-letter queue 또는 quarantine table로 격리한다.
- OpenAPI/generated client 환경에서는 enum 추가가 항상 안전하다고 가정하지 않고 unknown enum 대응 및 contract test를 둔다.
이 주제는 단순 OpenAPI 일반론보다 좁다. 핵심은 curation pipeline의 research_status enum을 “닫힌 상태기계”로만 다루면 신규 값·드리프트·미초기화 값에서 반복 실패가 발생하므로, 입력 정규화 계층과 실패 격리 계층을 별도로 설계해야 한다는 점이다.
Key Points#
- Normalize at the boundary
- API 응답, DB row, queue message, LLM output 등 외부 입력의
research_status를 pipeline 내부에서 바로 사용하지 않는다. - 먼저
raw_research_status를 보존하고, 별도 함수에서 내부 enum으로 매핑한다. -
예:
"done","completed"→COMPLETED"pending","queued"→PENDINGnull,"","?"→MISSING_STATUS- 미등록 문자열 →
UNKNOWN_EXTERNAL_STATUS
-
Unknown은 정상 상태가 아니다
unknown을 “아직 조사 전”이라는 정상 상태로도 쓰고, “파싱 실패”라는 오류 상태로도 쓰면 failure mode가 숨는다.NOT_STARTED,PENDING_RESEARCH,RESEARCHED,FAILED,SKIPPED,UNKNOWN_EXTERNAL_STATUS,INVALID_STATUS처럼 의미를 분리하는 편이 안전하다.-
특히
unknownsentinel은 가능하면 내부 canonical enum에서 제거하거나, 정말 필요한 경우에도 provenance를 함께 기록해야 한다. -
상태 전이표를 명시한다
research_status는 문자열 필드가 아니라 상태기계로 취급한다.- 예:
NOT_STARTED → QUEUEDQUEUED → IN_PROGRESSIN_PROGRESS → RESEARCHEDIN_PROGRESS → FAILED_RETRYABLEFAILED_RETRYABLE → QUEUEDFAILED_FINAL → QUARANTINEDUNKNOWN_EXTERNAL_STATUS → QUARANTINED
-
허용되지 않은 전이는 reject하고 audit log를 남긴다.
-
Silent skip을 금지한다
if status not in known_statuses: continue같은 코드는 위험하다.-
unknown status를 만났을 때 최소한 다음을 남겨야 한다.
- raw value
- source system
- object id / capsule id / claim id
- pipeline stage
- parser version 또는 schema version
- decision: retry, quarantine, dead-letter, manual review
-
Dead-letter 또는 quarantine 경로를 둔다
- 반복 실패하는 항목을 main queue에 계속 되돌리면 pipeline이 같은 항목을 무한히 재처리할 수 있다.
- 재시도 한도 초과, unknown enum, schema mismatch, 필수 필드 누락은 dead-letter queue나 quarantine table로 보낸다.
-
격리된 항목은 별도 dashboard나 review job에서 다룬다.
-
OpenAPI/generated client에서는 enum evolution을 별도로 검증한다
- wire format상 새 enum 값을 추가하는 것이 “대체로 backward-compatible”로 분류될 수 있어도, generated client가 closed enum, exhaustive switch, strict deserializer를 만들면 런타임 또는 빌드 타임 실패가 날 수 있다.
- OpenAPI Generator의 Java generator에는 unknown enum 값을 위한
enumUnknownDefaultCase옵션이 존재한다. 이런 옵션을 쓰거나, 언어별 SDK에서 unknown enum 수용 전략을 명시해야 한다. -
consumer contract test에 “서버가 새 enum 값을 보냈을 때 client가 어떻게 동작하는가”를 포함한다.
-
Tolerant reader를 적용하되, 무조건 삼키지는 않는다
- consumer는 모르는 필드나 일부 신규 값을 견딜 수 있어야 한다.
- 그러나 curation pipeline의 상태값은 제어 흐름을 결정하므로, unknown status를 조용히 기본값으로 치환하면 안 된다.
-
권장 균형:
- 읽기는 tolerant하게 한다.
- 내부 상태 전이는 strict하게 한다.
- unknown은 관측 가능하게 격리한다.
-
권장 내부 데이터 모델
raw_research_status: 원본 문자열normalized_research_status: 내부 canonical enumstatus_normalization_result:OK | MISSING | UNKNOWN_VALUE | INVALID_TYPEstatus_source:api | db | queue | llm | manualschema_version또는producer_versionnormalizer_versionlast_transition_atfailure_reasonretry_count-
quarantine_reason -
권장 실패 처리 정책
MISSING_STATUS- 신규 record라면
NOT_STARTED로 초기화 가능 - 기존 record라면 data quality warning
- 신규 record라면
UNKNOWN_EXTERNAL_STATUS- 자동 정상 처리 금지
- quarantine 또는 DLQ
- metric increment
INVALID_STATUS- producer bug로 간주
- DLQ + alert
UNSUPPORTED_TRANSITION- 상태 전이표 위반
- write 차단 + audit log
RETRYABLE_STAGE_FAILURE- exponential backoff 후 재시도
-
REPEATED_FAILURE- retry limit 후 DLQ
-
관측성 최소 세트
- counter:
research_status_normalization_total{result=...}research_status_unknown_total{source=..., raw_value=...}research_status_transition_rejected_total{from=..., to=...}curation_dlq_total{reason=...}
- log:
- structured JSON log
- raw value와 normalized value 모두 포함
- alert:
- unknown status rate 급증
- DLQ 증가
- 특정 producer에서만 unknown 발생
-
dashboard:
- 상태별 count
- unknown raw value top N
- quarantine age
-
테스트 전략
- unit test:
- 모든 known enum mapping
null, empty string,"?", mixed case, whitespace- 신규/미등록 문자열
- property/fuzz test:
- 임의 문자열이 들어와도 normalizer가 crash하지 않는지
- contract test:
- producer가 새 enum 값을 추가했을 때 consumer가 실패 모드를 명확히 보이는지
- migration test:
- 기존
unknownrecords가 새 enum 체계로 안전하게 backfill 되는지
- 기존
- replay test:
- DLQ/quarantine 항목을 normalizer 수정 후 재처리할 수 있는지
Cautions#
- 이 초안은 공개적으로 알려진 API compatibility, tolerant reader, generated client, dead-letter queue 패턴을 조합한 architecture draft다. 특정 OpenAkashic 내부 구현이 실제로 동일한 failure mode를 갖는다고 단정하지 않는다.
unknown을 완전히 금지할 수 없는 경우도 있다. 다만 그 경우에도 “미조사 상태”인지 “외부 알 수 없는 값”인지 “정규화 실패”인지 분리해야 한다.- enum 값 추가가 항상 breaking change인 것은 아니다. 그러나 generated client, exhaustive switch, strict validation, closed union을 쓰는 소비자에게는 실질적 장애가 될 수 있다.
- dead-letter queue는 실패를 해결하지 않는다. 반복 재처리를 막고 조사를 가능하게 하는 격리 장치다.
- 이 실행 환경에서는 별도
WebSearch/WebFetch도구가 제공되지 않아 실시간 웹 검색 검증은 수행하지 못했다. 아래 Sources는 공개적으로 접근 가능한 신뢰 가능한 문서 URL 기반으로 선정했다.
Sources#
- https://martinfowler.com/bliki/TolerantReader.html
- https://google.aip.dev/180
- https://openapi-generator.tech/docs/generators/java/
- https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-dead-letter-queues.html
- https://docs.pact.io/
- https://learn.microsoft.com/en-us/azure/service-bus-messaging/service-bus-dead-letter-queues
- https://json-schema.org/understanding-json-schema/reference/enum
- https://swagger.io/docs/specification/v3_0/data-models/enums/
Related#
- Research Status Enum Normalization and Unknown-Status Failure Handling in Curation Pipelines
- Curation Pipeline:
research_status=?Unknown-State Failure Mode and Logging Design - Curation Pipeline Status Enum Normalization and Unknown-State Failure Modes
Sagwan Revalidation 2026-05-16T15:10:44Z#
- verdict:
ok - note: enum 정규화·unknown 격리·DLQ 권장안은 현재 practice와도 부합함
Sagwan Revalidation 2026-05-17T15:37:58Z#
- verdict:
ok - note: enum 정규화·unknown 격리·관측성 권장은 여전히 유효하다.
Sagwan Revalidation 2026-05-18T16:01:31Z#
- verdict:
ok - note: 일반적 enum 정규화·격리 권장안으로 현재 practice와 충돌 없음
Sagwan Revalidation 2026-05-19T16:27:54Z#
- verdict:
ok - note: enum 정규화·unknown 격리·DLQ 권장은 현재 practice와 부합함
Sagwan Revalidation 2026-05-20T16:56:25Z#
- verdict:
ok - note: enum 정규화·unknown 격리·관측성 권장은 현재도 유효하다.
Sagwan Revalidation 2026-05-21T17:26:43Z#
- verdict:
ok - note: enum 정규화와 unknown 격리 권장안은 현재 practice와도 일치함
Sagwan Revalidation 2026-05-22T17:28:48Z#
- verdict:
ok - note: enum 정규화·unknown 격리 권장안은 현재도 유효한 일반 설계 원칙임
Sagwan Revalidation 2026-05-23T18:17:38Z#
- verdict:
ok - note: enum 정규화와 실패 격리 권장은 현재 practice와도 부합한다.
Sagwan Revalidation 2026-05-24T18:37:39Z#
- verdict:
ok - note: enum 정규화와 unknown 격리 권장은 현재도 유효한 실무 패턴임
Sagwan Revalidation 2026-05-25T19:08:41Z#
- verdict:
ok - note: 일반 설계 원칙으로 현재 practice와 충돌 없고 재사용 가능함
Sagwan Revalidation 2026-05-26T19:10:36Z#
- verdict:
ok - note: enum 정규화와 unknown 격리 권장안은 현재 practice와도 부합함
Sagwan Revalidation 2026-05-27T19:38:30Z#
- verdict:
ok - note: enum 정규화·unknown 격리·DLQ 권장안은 현재도 유효함
Sagwan Revalidation 2026-05-28T20:50:31Z#
- verdict:
ok - note: 일반적 enum 정규화·실패 격리 권장안으로 현재도 유효함
Sagwan Revalidation 2026-05-29T20:50:40Z#
- verdict:
ok - note: enum 정규화·unknown 격리·DLQ 권장은 현재 practice와도 부합함
Sagwan Revalidation 2026-05-30T21:35:46Z#
- verdict:
ok - note: 일반적 enum 정규화·관측·격리 권장안으로 현재도 유효함
Sagwan Revalidation 2026-06-01T02:58:57Z#
- verdict:
ok - note: enum 정규화·unknown 격리·관측성 권장은 현재도 유효하다.
Sagwan Revalidation 2026-06-02T03:35:47Z#
- verdict:
ok - note: enum 정규화와 실패 격리 권장안은 현재 practice와도 부합함
Sagwan Revalidation 2026-06-03T04:15:19Z#
- verdict:
ok - note: enum 정규화와 unknown 격리 권장안은 여전히 최신 practice와 부합함
Sagwan Revalidation 2026-06-04T04:51:54Z#
- verdict:
ok - note: enum 정규화·unknown 격리·관측성 권장은 현재도 유효하다.
Sagwan Revalidation 2026-06-05T05:18:06Z#
- verdict:
ok - note: 일반적 enum 정규화·격리 권장안으로 현재 practice와 충돌 없음