[이슈 #52] AI 재고판정 산출물 → DB inventory handoff 변환·반영 (부서 접기 + SS/ROP 재계산) - #53
Conversation
DB 의 mu/sigma/SS/ROP 는 AI 산출물이 아니라 backend 스톱갭
(scripts/fix_inventory_stats.py)이 계산한 값이다. 그래서 인공 바닥값이 그대로
남아 있다 — 운영 DB 실측 2026-07-30 기준 mu<=0.5 가 296,537 / 409,459행(72.4%),
sigma<=0.1 이 201,814행. AI 정책은 이미 바닥값을 0 으로 뒀는데(inventory-status-v1.1,
mean_daily_usage_floor 0.0) DB 로 오는 경로가 없었다.
두 쪽 키 단위가 달라 그대로 붓지 못한다.
AI : (institution_code, department, item_code) 416,128 시계열
DB : (institution_id, standard_code) 409,459행 — 부서 축 없음
compute_inventory_policy_handoff.py — 부서 접기
AI 산출물이 시계열별 모멘트 합을 들고 있어 근사 없이 재계산된다.
출고합·제곱합 SUM · 첫관측일 MIN → 노출일수 재산정
mu = 출고합/노출일수 · sigma = sqrt(제곱합/노출일수 - mu^2)
inventory_status.py 의 _prepare_series_status 와 같은 식이다.
합성 입력으로 손계산 대조 통과(mu 0.27360 / sigma 1.54516).
sigma 는 부서 2개 이상 조합에서 부서간 공분산을 무시한다(SS 과소 방향). 해당 비율을
실행 때 출력하도록 했다.
⚠️ 기관 매핑 오매핑 차단을 추가했다. 기존 handoff 스크립트는 익명코드↔institution_id
를 정렬-zip 으로 맞추면서 개수 검사가 없었다. AI 산출물은 3,530 기관인데 전체는
3,598 이라 산출물만으로 zip 하면 전부 밀린다. 개수가 어긋나면 중단한다.
2열 매핑(INST_CODE_MAP)을 주면 정렬 가정 자체를 없앨 수 있다.
apply_inventory_policy.py — mu/sigma 교체 + SS/ROP 재계산
mu 만 갈아끼우면 안 된다. 기존 apply_* 는 컬럼만 덧칠하고
apply_supply_risk_policy.py 는 "z_used/lead_time_used/SS/ROP는 안 건드림"이라고
명시돼 있어, SS/ROP 가 옛 mu 기준으로 남는다.
실측(헤모포스정 WMD0317947): mu 63.12 · mu_corrected 70.18 · z 2.05 · L 16.2 ·
저장 ss 1,817.7 / rop 2,843.5 → (rop-ss)/L = 63.32 = mu 기준.
ROP 는 mu 로, 화면 소진곡선은 mu_corrected 로 그려져 기준이 어긋나 있었다
(frontend#43 에서 화면 쪽 임시 대응).
ai_policy_adapter.py 에 문서화된 계약과 같은 식으로 재계산한다.
SS = z*sigma*sqrt(L) · ROP = mu*L+SS · target = mu*(L+1)+SS
z_used·lead_time_used·supply_risk_level·status 는 건드리지 않는다.
발주 억제는 AI 정책대로 DORMANT/NOT_OPERATED → 0.
안전장치: DRY_RUN 기본 1, 조인율 90% 미만이면 중단,
반영 후 (rop-ss)/L 과 mu 의 불일치 행수를 출력(0 이어야 한다).
알려진 편차: DATA_MISSING/stale 은 정책상 권고량 null 이지만
inventory.order_recommendation 이 NOT NULL 이라 0 으로 넣고 건수를 보고한다.
null 계약을 지키려면 backend DDL 변경이 필요하다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
스키마 제약을 푸는 PR 을 올렸습니다 — DGU-TeamLex/backend#72. 머지되면 이 PR 의 |
|
이 PR 의 SS/ROP 재계산 부분을 보류하려 합니다. 확인 없이 진행한 부분이라 먼저 여쭙니다.
그런데 제안: 이 PR 범위를 다르게 보시면 알려주세요. 지금은 손대지 않고 답을 기다리겠습니다. |
배경 — DB 의 숫자는 AI 산출물이 아니다
코드를 따라가 보니
inventory의mu/sigma/z_used/lead_time_used/ss/rop는 backend 스톱갭(scripts/fix_inventory_stats.py)이 계산한 값입니다.ai_policy_adapter.py주석이 그 상황을 그대로 적어놨습니다.AI 쪽은
inventory-status-v1.1에서 이미mean_daily_usage_floor: 0.0으로 바닥값을 없앴는데, 그 결과가 DB 로 오는 경로가 없습니다. 운영 DB 실측(2026-07-30):inventory전체mu <= 0.5sigma <= 0.1왜 그대로 붓지 못하나 — 키 단위가 다르다
1)
compute_inventory_policy_handoff.py— 부서 접기AI 산출물이 시계열별 모멘트 합(
all_time_normal_outbound,normal_outbound_squared_sum)을 들고 있어서 근사 없이 재계산됩니다.inventory_status.py의_prepare_series_status와 같은 식입니다. 합성 입력으로 손계산 대조했습니다 —mu 0.27360 / sigma 1.54516일치.알려진 한계: 부서가 2개 이상인 조합에서 sigma 는 부서간 공분산을 무시합니다(SS 과소 방향). 해당 비율을 실행 때 출력합니다.
기존 스크립트의 오매핑 위험을 막았습니다
기존 handoff 는 익명 기관코드 ↔
institution_id를 정렬-zip 으로 맞추는데 개수 검사가 없습니다. AI 산출물은 3,530 기관이고 전체는 3,598 이라, 산출물만으로 zip 하면 전부 밀립니다. 개수가 어긋나면 중단하도록 했고, 2열 매핑(INST_CODE_MAP)을 주면 정렬 가정 자체를 없앨 수 있습니다.2)
apply_inventory_policy.py— mu/sigma 교체 + SS/ROP 재계산mu 만 갈아끼우면 안 됩니다.
apply_supply_risk_policy.py는 주석에 "z_used/lead_time_used/SS/ROP는 안 건드림"이라고 명시돼 있어, SS/ROP 가 옛 mu 기준으로 남습니다.실측(헤모포스정
WMD0317947):ROP 는
mu로, 화면 소진곡선은mu_corrected로 그려져 기준이 어긋나 있었습니다(frontend#43 에서 화면 쪽 임시 대응 완료). mu 만 바꾸고 SS/ROP 를 두면 같은 어긋남이 재발합니다.ai_policy_adapter.py에 문서화된 계약과 같은 식으로 재계산합니다.z_used·lead_time_used·supply_risk_level·status는 건드리지 않습니다. 발주 억제는 AI 정책대로DORMANT/NOT_OPERATED→ 0.안전장치:
DRY_RUN기본 1 · 조인율 90% 미만이면 중단 · 반영 후(rop−ss)/L과mu불일치 행수 출력(0 이어야 함).실행에 필요한 것 (부탁드립니다)
outputs/가.gitignore라 산출물이 레포에 없어서 아직 돌리지 못했습니다. 둘 중 하나만 주시면 바로 돌려서 결과를 붙이겠습니다.outputs/stock_inventory_status.csv(또는 접근 경로)institution_id2열 매핑 — 있으면 정렬-zip 을 영구히 안 써도 됩니다기존
data/handoff/mu_forecast.csv·zero_stock_reason.csv처럼 handoff CSV 를 커밋해주시는 것도 같은 효과입니다.알려진 편차 — backend DDL 필요
DATA_MISSING/ stale 은 AI 정책상 권고량null이지만inventory.order_recommendation이NOT NULL입니다. 지금은 0 으로 넣고 건수를 보고합니다. null 계약을 지키려면 backend 스키마 변경이 필요합니다.Type
PR Checklist