o2o-negosium-original/schedules/anchoring/TODO.md
민헌 84786134c2 docs(anchoring): 후속 과제 TODO 정리 — 계단식 가격구간·anchoring_records
두 과제 모두 정책 재확정 + 스펙 v1.3 개정 사안으로 기록:

1. 정적 테이블 가격구간 계단식 재설계 — 고가 구간에서 3,000원 균일 폭이
   무의미(표본 미집적·희소 칸 가중). 변경 범위(base json·bracket 산식·검증·
   테스트·문서·negodata 재전달)와 핵심 리스크(이력의 bracket 인덱스 호환 —
   조정 이력 쌓이기 전 개편이 최저비용) 명시
2. anchoring_records — 회사별 운영 중 업데이트된 앵커링 값 전체 조회 테이블.
   성격(현재값 스냅샷 vs 시계열 사본)·rate_adjustments 와의 역할 분리(파생
   테이블, 재구축 가능)·쓰기 시점·무조정 칸 표현 등 설계 결정 항목과
   과제 1과의 순서 조율 명시

README 에 TODO 안내 추가.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 17:27:47 +09:00

82 lines
4.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# TODO — 앵커링 모듈 후속 과제
> 두 과제 모두 **정책 재확정 + 스펙(v1.3) 개정 사안**이다. 현재 규범(`docs/개발용.md` §12)은
> 정적 테이블 변경·파라미터 조정을 봉인하고 있으므로, 착수 전 정책 확정 → 문서 개정 → 구현 순서를 지킨다.
> 두 과제 다 **운영 데이터(조정 이력)가 쌓이기 전에 확정하는 것이 가장 저렴하다** — negodata 적용 전이 적기.
---
## 1. 정적 기본 테이블의 가격구간을 계단식으로 재설계
### 배경
현재 `resources/anchoring_base.json` 은 0원~1억을 **균일 3,000원 폭 33,334칸**으로 나눈다.
저가 구간에서는 3,000원 구분이 유효하지만, 고가 구간(예: 9,900만 원대)에서 3,000원 차이는
협상 관점에서 의미가 없다. 결과적으로:
- 고가 칸은 표본이 거의 안 모여 **영원히 이월**만 반복(희소 칸 문제를 구조적으로 가중)
- 33,334칸 중 실질 사용 칸이 극소수 — 테이블·캐시·인덱스가 불필요하게 큼
### 방향 (예시 — 정책 확정 필요)
가격대별로 구간 폭을 넓히는 계단식. 예:
| 가격대 | 구간 폭(예시) |
|---|---|
| ~ 100만 | 3,000원 |
| 100만 ~ 1,000만 | 30,000원 |
| 1,000만 ~ 1억 | 300,000원 |
| 1억 초과 | 마지막 구간 편입(현행 유지) |
정확한 경계·폭은 실거래 목표가 분포를 보고 정책으로 확정한다.
### 착수 시 변경 범위 (전부 이 모듈 안 + 문서)
- [ ] `resources/anchoring_base.json` — 구간표 재생성(행 수 대폭 감소)
- [ ] `service.calc_bracket_index` — `// 3000` 단순 나눗셈 → 계단식 경계 탐색(이분 탐색 등)으로 교체
- [ ] `base_table._validate` — "upper_bound == idx×3000" 검증을 새 규약으로 교체
- [ ] `constants` — PRICE_BRACKET_UNIT/BRACKET_INDEX_MAX 등 상수 재정의
- [ ] 골든 테스트 `tests/test_core.py` §11.2 — 경계 케이스 재작성
- [ ] 문서 — `docs/개발용.md` §2·§4.1, `docs/기획용.md` §2, `docs/워크플로우.md` 칸 설명
- [ ] negodata 이식본(reader) 재전달 — `docs/인수인계.md` 갱신
### ⚠️ 이력 호환성 (핵심 리스크)
`anchoring.rate_adjustments.price_bracket_index` 와 Redis 키의 인덱스 의미가 바뀐다.
**이미 조정 이력이 쌓인 뒤에 개편하면** 구 인덱스 ↔ 신 인덱스 해석이 섞이므로:
- 이력이 쌓이기 전(negodata 적용 전)에 개편하거나,
- 이후라면 구간표에 버전을 부여(`bracket_schema_version` 컬럼 또는 신규 테이블 세대 구분)하고
기존 이력의 재매핑/동결 전략을 함께 설계해야 한다.
---
## 2. `anchoring_records` — 회사별 앵커링 값 전체 조회 테이블
### 배경
현재 `anchoring.rate_adjustments` 는 **"조정 사건" 로그**다 — 값이 바뀐 칸만 행이 생긴다.
"A사의 모든 칸(또는 운영 중 사용된 칸)의 앵커링 값이 지금/과거에 얼마였나"를 한 번에
조회하려면, 조정 이력 + 정적 테이블 시작값을 합성해야 해서 조회(대시보드·관리 화면)에
불편하다. 회사별로 운영되며 업데이트된 모든 앵커링 값을 바로 조회할 수 있는 테이블이 필요하다.
### 설계 시 결정해야 할 것 (구현이 크게 바뀔 수 있음)
- [ ] **성격 확정**: ① 칸별 "현재값" 스냅샷(UPSERT — 조회 최적) ② 값 변경 시계열의 조회
친화 사본(append) ③ 둘 다 — 무엇이 필요한지 조회 요구사항(대시보드/API 화면)부터 정의
- [ ] **rate_adjustments 와의 역할 분리**: records 는 **파생(조회용) 테이블**로 두고
진실 원천은 rate_adjustments 유지가 안전 — records 는 언제든 이력에서 재구축 가능해야
하며, append-only 보호 대상(§12)에는 포함하지 않는다
- [ ] **쓰기 주체·시점**: 배치가 조정 트랜잭션에 함께 기록할지(정합 우선), 커밋 후
best-effort 로 기록할지(조정 경로 무손대 우선 — 재구축 가능하므로 후자도 충분)
- [ ] **무조정 칸 표현**: 시작값(10‰) 그대로인 칸을 행으로 둘지(회사 온보딩 시 33,334행
선생성 — 구 설계의 JSONB 문제 재발 주의), 조회 시 정적 테이블과 합성할지
- [ ] 과제 1(구간 개편)과 **순서 조율** — records 스키마에 bracket 인덱스가 들어가므로
구간 개편 후에 만드는 것이 이중 작업을 피한다
### 참고
- 임시로는 현행 SQL 조회로 동일 정보를 얻을 수 있다: `docs/운영및유지보수.md` §8
(값 변천사 = ①, 현재값 = 칸별 최신 행 + 없으면 시작값 10‰)
- 스펙 반영 위치: `docs/개발용.md` §6(스키마)·§8(배치 절차에 기록 단계 추가)