-
Notifications
You must be signed in to change notification settings - Fork 0
추출 실패 code 전수 매핑 + reason 을 운영 액션 기준으로 재분류 #938
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
34 changes: 34 additions & 0 deletions
34
src/main/kotlin/com/depromeet/piki/product/service/ExtractionFailureBucket.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| package com.depromeet.piki.product.service | ||
|
|
||
| import com.depromeet.piki.common.exception.ErrorCode | ||
|
|
||
| // 확정 실패(원격 422)를 **운영 액션 축**으로 나눈 분류(#936). "이 숫자가 늘면 누가 무엇을 하는가"가 기준이라, | ||
| // 실패의 기술적 원인이 아니라 대응이 같은 것끼리 묶인다. | ||
| // 계약 카탈로그(shared-infra/contracts/extraction-error-codes.yaml)의 bucket 과 1:1 이고, 파싱 메트릭의 | ||
| // reason 라벨(ItemParsingMetrics)도 여기서 파생한다 — 셋(카탈로그·예외·메트릭)이 어긋나면 | ||
| // ExtractionErrorCatalogTest 가 잡는다. | ||
| enum class ExtractionFailureBucket { | ||
| // 사용자가 상품 아닌 걸 넣었다. 정상 트래픽이라 할 일이 없다. | ||
| NOT_PRODUCT, | ||
|
|
||
| // 우리 구성으로 그 페이지를 못 읽었다(빈 셸·추출할 본문 없음). 늘면 도메인 허가 후보를 본다. | ||
| UNREADABLE, | ||
|
|
||
| // 대상이 우리를 막았다. 늘면 UNSUPPORTED 정책 후보를 본다. | ||
| BLOCKED, | ||
|
|
||
| // 추출은 됐는데 값을 믿을 수 없다. 늘면 모델·프롬프트·검증 규칙을 본다. | ||
| EXTRACT_QUALITY, | ||
|
|
||
| // 우리 버그이거나 우리 방어가 발동했다. 늘면 코드를 조사한다. | ||
| INTERNAL_ERROR, | ||
| } | ||
|
|
||
| // 확정 실패 예외가 자기 bucket 을 스스로 밝히게 하는 ErrorCode. 예외 클래스가 늘어도 워커는 이 인터페이스만 | ||
| // 보므로 reason 파생 경로가 한 줄로 유지되고, bucket 은 code 정의 옆(single source)에 박힌다. | ||
| // | ||
| // bucket 이 nullable 인 이유: 일시(transient) code 는 bucket 이 없다(카탈로그도 같은 모양). 일시 실패는 | ||
| // 소유권 반납으로 되살아나 종결 집계(reason)에 닿지 않고, 상한을 소진하면 recover 가 retry_exhausted 로 센다. | ||
| interface ExtractionFailureCode : ErrorCode { | ||
| val bucket: ExtractionFailureBucket? | ||
| } |
36 changes: 31 additions & 5 deletions
36
src/main/kotlin/com/depromeet/piki/product/service/ProductSnapshotErrorCode.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,25 +1,51 @@ | ||
| package com.depromeet.piki.product.service | ||
|
|
||
| import com.depromeet.piki.common.exception.ErrorCategory | ||
| import com.depromeet.piki.common.exception.ErrorCode | ||
|
|
||
| // ProductSnapshotException 의 code 배정표(에픽 #728). 번호는 append-only — 재배치·결번 침범 금지. | ||
| // | ||
| // ⚠️ 이 enum 은 ErrorCodeRegistry.all 에 **의도적으로 등록하지 않는다**(AnnouncementImageErrorCode 와 같은 선례). | ||
| // 유일한 생성 경로인 ProductSnapshot.fromExtracted · RemoteExtractionContract.translate 는 비동기 파싱 | ||
| // 워커(AsyncItemParsingWorker · AsyncImageParsingWorker)에서만 호출된다 — 워커가 예외를 잡아 item 을 FAILED 로 | ||
| // 전이시키고 메트릭 reason=not_product 로 집계할 뿐, GlobalExceptionHandler 를 거치지 않아 응답 code 로 나가지 않는다. | ||
| // 전이시키고 메트릭 reason(아래 bucket 에서 파생)으로 집계할 뿐, GlobalExceptionHandler 를 거치지 않아 응답 code 로 나가지 않는다. | ||
| // 클라가 절대 받을 수 없는 code 를 공개 카탈로그에 넣으면 code→문구 매핑에 노이즈만 된다. | ||
| // 여기서 code 를 부여하는 목적은 오직 예외 클래스 모양을 다른 도메인 예외와 통일(errorCode 참조)하는 것뿐이다. | ||
| // | ||
| // bucket 은 그 실패를 메트릭에서 무엇으로 셀지의 정본이다(#936) — 파싱 메트릭 reason 이 여기서 파생하므로, | ||
| // code 를 더할 때 bucket 도 함께 정한다. 원격 code → 여기의 어느 엔트리인지는 RemoteExtractionContract 가 정한다. | ||
| enum class ProductSnapshotErrorCode( | ||
| override val code: String, | ||
| override val category: ErrorCategory, | ||
| override val message: String, | ||
| ) : ErrorCode { | ||
| override val bucket: ExtractionFailureBucket, | ||
| ) : ExtractionFailureCode { | ||
| // LLM 이 "상품 페이지가 아님"으로 판정. 링크 재등록·재시도 모두 무의미. | ||
| NOT_PRODUCT_PAGE("SNAPSHOT-001", ErrorCategory.INVALID_INPUT, "상품 페이지 링크만 등록할 수 있어요."), | ||
| NOT_PRODUCT_PAGE( | ||
| "SNAPSHOT-001", | ||
| ErrorCategory.INVALID_INPUT, | ||
| "상품 페이지 링크만 등록할 수 있어요.", | ||
| ExtractionFailureBucket.NOT_PRODUCT, | ||
| ), | ||
|
|
||
| // 추출값이 유효 범위(가격 음수, 컬럼 길이 초과 등)를 벗어남. 추출 결과를 신뢰할 수 없다. | ||
| // 구체 사유(어느 필드가 왜)는 message 에 담지 않고 로그로 남긴다. | ||
| UNTRUSTWORTHY_VALUE("SNAPSHOT-002", ErrorCategory.INVALID_INPUT, "상품 정보를 확인하지 못했어요. 직접 입력해 주세요."), | ||
| // bucket 이 not_product 가 아닌 이유(#936): "상품 아님"과 성격이 다르고 — 추출 자체는 됐는데 값을 못 믿는 것 — | ||
| // 대응도 모델·프롬프트·검증 규칙 쪽이라, 한 통에 두면 "상품 아님" 지표가 두 배로 부풀어 판단을 흐린다. | ||
| UNTRUSTWORTHY_VALUE( | ||
| "SNAPSHOT-002", | ||
| ErrorCategory.INVALID_INPUT, | ||
| "상품 정보를 확인하지 못했어요. 직접 입력해 주세요.", | ||
| ExtractionFailureBucket.EXTRACT_QUALITY, | ||
| ), | ||
|
|
||
| // 우리가 그 페이지에서 읽어낼 본문을 얻지 못함(데이터 없는 CSR 셸·가시 텍스트 부재). 상품이 아닌 게 아니라 | ||
| // **지금 우리 구성으로 못 읽는** 것이라 도메인 허가 후보를 찾는 신호다. | ||
| // message 는 UNTRUSTWORTHY_VALUE 와 같다 — 사용자가 취할 행동(직접 입력)이 같고, 구분은 detail 이 아니라 | ||
| // bucket·로그가 진다(CLAUDE.md 메시지 톤). | ||
| NO_EXTRACTABLE_CONTENT( | ||
| "SNAPSHOT-003", | ||
| ErrorCategory.INVALID_INPUT, | ||
| "상품 정보를 확인하지 못했어요. 직접 입력해 주세요.", | ||
| ExtractionFailureBucket.UNREADABLE, | ||
| ), | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
Repository: TeamPiKi/core
Length of output: 6040
🏁 Script executed:
Repository: TeamPiKi/core
Length of output: 50369
🏁 Script executed:
Repository: TeamPiKi/core
Length of output: 725
🏁 Script executed:
Repository: TeamPiKi/core
Length of output: 632
Error를 추출 실패 경로에서 전파하세요.두 워커의 추출 호출을
runCatching대신try/catch (e: Exception)으로 감싸세요. 현재OutOfMemoryError가FAILED전이와 메트릭 기록으로 전달됩니다. 이미지 워커는 이후 raw 객체까지 삭제할 수 있습니다.ItemParsingMetrics.reasonOf는 일반Exception의internal_errorfallback만 유지하고,OutOfMemoryError테스트 기대값은 제거하세요. 대신 두 워커에서Error가 전파되는 테스트를 추가하세요.📍 Affects 4 files
src/main/kotlin/com/depromeet/piki/item/service/ItemParsingMetrics.kt#L68-L72(this comment)src/main/kotlin/com/depromeet/piki/item/service/AsyncImageParsingWorker.kt#L155-L156src/main/kotlin/com/depromeet/piki/item/service/AsyncItemParsingWorker.kt#L155-L157src/test/kotlin/com/depromeet/piki/item/service/ItemParsingMetricsTest.kt#L42-L50🤖 Prompt for AI Agents
Source: Learnings