Skip to content

fix(bulk-approval): 2018~19 원장 투입 시 일괄승인이 전량 중단되던 문제 — 분류 커버리지 0.94% → 100% - #67

Open
choigod1023 wants to merge 1 commit into
devfrom
fix/bulk-approval-history-only-keys
Open

fix(bulk-approval): 2018~19 원장 투입 시 일괄승인이 전량 중단되던 문제 — 분류 커버리지 0.94% → 100%#67
choigod1023 wants to merge 1 commit into
devfrom
fix/bulk-approval-history-only-keys

Conversation

@choigod1023

Copy link
Copy Markdown
Contributor

Description

2018~19 원장을 투입하자 src.item_bulk_approval매번 예외로 죽어서 일괄승인 단계가 한 번도 완주하지 못했습니다. 그 결과 파이프라인 전체가 config.py 의 seed 경로(78행 택소노미)로 떨어져 있었고, 분류 커버리지가 0.94% 였습니다.

원인을 찾아 고치고 실제로 끝까지 돌렸습니다. 분류 커버리지 0.94% → 100.00%, 뉴스 결합 도달 0% → 출고량 기준 97.64% 입니다.

무엇이 잘못돼 있었나

build_bulk_material_mapping 은 원자재 후보가 전부 운영 월별재고의 stock_item_key 로 해소된다고 가정하고, 하나라도 어긋나면 예외를 던졌습니다.

그런데 품목 정규화는 201819 보조 원장까지 포함해 로컬 품목키를 만드는 반면 stock_monthly.parquet 은 202425 운영 구간만 담습니다. 실측하면 이렇습니다.

구분 키 수
local 후보 전체 505,669
2024~25 에 존재 409,519
2018~19 에만 존재 96,150
양쪽 다 없음 0

양쪽 다 없는 키가 0개라는 점이 중요합니다. 데이터 오염이 아니라 기간 범위 차이이고, 단일 기간만 쓰던 동안에는 이 가정이 우연히 성립했습니다.

조치

과거에만 존재한 품목은 붙일 stock_item_key 가 없으므로 제외하되, 조용히 버리지 않고 건수를 리포트에 남깁니다. 하나도 해소되지 않는 경우는 설정 오류이므로 여전히 실패시킵니다.

리포트 추가 항목 3개입니다.

  • unresolved_stock_key_candidate_rows
  • unresolved_stock_key_local_item_count
  • resolved_candidate_rows

실행 결과 미해소 138,139행 / 96,150 로컬품목으로 기록됐고, 예상치와 정확히 일치합니다.

실행 결과

python -m src.item_bulk_approval --apply 가 처음으로 완주했습니다.

항목 이전(seed) 이후(bulk)
택소노미 행 78 438,446
승인 로컬품목 4,346 505,669
원자재 매핑 파일 없음 634,655행 / 416,078 키
뉴스 결합 가능 행 0 524,763

이어서 inventory_status 를 재실행한 결과입니다.

지표 이전 이후
classification_coverage 0.9427% 100.0000%
urgent_shortage_count 10 753
COVERED_BY_APPROVED_EQUIVALENT_STOCK 1 220

긴급부족이 10건이던 것은 urgent_shortage_rulerequires_forecastable_item 이 분류를 요구하는데 분류가 0.94%뿐이라 대부분 판정 자체를 못 받았기 때문이었습니다.

안전장치는 그대로입니다. automatic_order_eligible_count4,346 유지 — 자동발주는 여전히 외부근거 승인분에만 열려 있고, 일괄승인은 후보 수용이지 사실 검증이 아니라는 정책 문구도 리포트 warnings 에 그대로 출력됩니다.

뉴스 축에 미치는 영향

news_risk_scorereligibility_column="news_signal_eligible" 로 이미 올바르게 구현돼 있었습니다. 코드 문제가 아니라 매핑 파일이 만들어지지 않아 비어 있던 것입니다.

지표 이전 이후
도달 stock_item_key 0 323,289 (시리즈의 77.69%)
출고량 가중 도달 0.00% 97.64%

테스트

tests/test_item_bulk_approval.py 에 2건 추가했습니다.

  • test_history_only_candidates_are_dropped_and_counted — 과거 전용 후보가 제외되고 리포트에 집계되는지
  • test_no_resolvable_candidate_still_fails_loudly — 전부 미해소면 여전히 실패하는지
Ran 4 tests in 0.240s
OK

To Reviewer

의견 부탁드립니다.

  1. 제외가 맞는 판단인지 — 2018~19 전용 품목에 운영 원자재 매핑을 붙일 이유가 없다고 보고 제외했습니다. 반대로 과거 구간 분석을 위해 보조 원장까지 포함한 매핑이 필요하다면 방향을 바꾸겠습니다.
  2. seed → bulk 전환을 정본으로 둘지 — 현재는 마커 파일(data/processed/item_bulk_approval_active.json) 존재 여부로 전환됩니다. 일괄승인이 이제 완주하므로 파이프라인 표준 실행 순서에 이 단계를 명시하는 편이 좋겠다고 봅니다. 이번 PR 에는 넣지 않았습니다.
  3. 긴급부족 753건의 타당성 — 분류가 열리면서 판정 대상이 늘어난 결과입니다. 실제 운영 관점에서 이 규모가 타당한지 확인 부탁드립니다.

Type

  • 새로운 기능
  • 버그 수정
  • 리팩토링
  • 문서
  • 의존성 추가/수정

PR Checklist

  • Commit Message Convention을 준수했습니다.
  • Code Convention을 준수했습니다.
  • 변경한 기능이 잘 동작하는지 테스트했습니다. — 단위 테스트 4건 통과 + 실데이터 일괄승인 완주 및 재고판정 재실행 확인

`build_bulk_material_mapping` 은 원자재 후보 전부가 운영 월별재고의
stock_item_key 로 해소되어야 한다고 가정하고, 하나라도 어긋나면 raise 했다.

품목 정규화는 2018~19 보조 원장까지 포함해 로컬 품목키를 만들지만
`stock_monthly.parquet` 은 2024~25 운영 구간만 담는다. 2018~19 원장을
투입하자 후보 505,669키 중 96,150키(2018~19 전용)가 해소되지 않아
일괄승인 단계 전체가 실패했다. 양쪽 어디에도 없는 키는 0개였다.

과거에만 존재한 품목은 붙일 stock_item_key 가 없으므로 조용히 버리는
대신 건수를 리포트에 남기고 진행한다. 하나도 해소되지 않는 경우는
설정 오류이므로 여전히 실패시킨다.

리포트 추가 항목:
- unresolved_stock_key_candidate_rows
- unresolved_stock_key_local_item_count
- resolved_candidate_rows

실행 결과 미해소 138,139행 / 96,150 로컬품목으로 기록되었고,
일괄승인이 처음으로 끝까지 완주했다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@sehyeon03

Copy link
Copy Markdown
Contributor

2026-08-10 신규 PR 검토

결론: 문제 방향은 맞지만 현재 구현은 병합 전 수정이 필요합니다. 관련 테스트 4개와 네 PR 통합 브랜치 전체 244개 테스트는 통과했습니다. 그러나 새 로직은 “2018~19 전용”임을 확인하지 않고 모든 stock key 미매칭을 허용합니다.

Blocking: 미매칭이 과거 전용이라는 증명이 없습니다

build_bulk_material_mapping()은 candidates와 2024~25 monthly stock만 받기 때문에, unmatched가 과거 전용인지 현재자료 누락·키 오타·상류 corruption인지 구분할 수 없습니다. 유효 후보 1개와 I1::CURRENT_TYPO 1개를 함께 넣어 재현하면 함수는 성공하고 오타 후보를 조용히 버립니다.

mapped=1
input_candidate_rows=2
approved_candidate_rows=2
unresolved_stock_key_candidate_rows=1

즉 하나라도 resolve되면 예상하지 못한 미매칭도 통과하며, approved_candidate_rows=2all_material_candidates_approved도 실제 mapping 1행과 모순됩니다. 현재 테스트의 HIST 주석은 행이 진짜 과거 원장에 존재하는지를 검증하지 않습니다.

수정 권장

  1. current/historical local key universe 또는 candidate의 명시적 data_period를 입력으로 받아 history_only_excludedunexpected_unresolved를 구분
  2. 검증된 history-only만 제외, 양쪽 어디에도 없거나 current에 있어야 하는 미매칭은 한 건이라도 예외
  3. approved_candidate_rows를 실제 resolved candidate 수로 고치고 input = resolved + history-only excluded가 성립하는 reconciliation gate 추가
  4. many-to-many 확장 행 수와 unique local/stock key 수를 별도 이름으로 보고
  5. “분류 커버리지 100%”는 정확도나 외부검증률이 아니라 workflow approval key coverage임을 명시하고, 긴급부족 753건도 evidence status별로 분리
  6. 유효 current + 검증된 history-only + 양쪽에 없는 typo 혼합 회귀 테스트 추가

과거 전용 96,150키를 운영 mapping에서 제외한다는 정책 자체에는 동의합니다. 다만 제외 사유를 코드가 증명하고 예상 밖 미매칭은 계속 fail-closed해야 합니다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants