- 반응형: 최소 폭 1350→1024px, max-[1350px]/max-[1180px] 2단계 축소
- 사이드바 350→310→280, 우측 메뉴 360→320→280, 채팅 거터 140/126→80/72→48/40 (헤더 패딩 동기)
- 가격·할인율 입력 min-w 480→420→320, 가운데 버튼 패딩·최소폭 축소, 상품목록 버튼 1180px 미만 아이콘만
- 상품 이미지 220→200, 사이드바 정보 행 값 영역 고정 150px → flex-1
- 리드타임: formatLeadTime 헬퍼 신설 — 좌측 상품정보·협상 결과 요약 카드에 "일" 접미 표시
- 인디케이터: init 의 session_status 를 스토어에 적재, 협상중(IN_PROGRESS) 세션에서만 표시
- 사이드바 정보 영역 의미 없는 가로 스크롤 제거 (shrink 금지 컬럼 + overflow-x 자동 계산이 원인)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- 상품목록 버튼 래퍼에 pr-[16px] 추가 — 채팅 스크롤바 오른쪽 끝과 정렬
- 상단 pt-[64px] 를 스크롤 컨테이너 안쪽으로 이동 — 첫 메시지는 협상절차 카드와 높이 유지, 스크롤 시 여백 없이 맨 위까지 표시
- chat-scroll 스크롤바 트랙에 margin-top 64px — 스크롤바 시작 높이를 협상절차 카드 상단과 일치
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- config.py: APP_ENV(기본 local) 기반 config.{APP_ENV}.toml 로드 — backend/negodata 와 동일 관례
- dev/prod 는 파일 부재 시 기동 즉시 중단(FileNotFoundError) — 오타·미배치 상태로
코드 기본값(로컬 DB)에 붙는 무증상 사고 방지. local 만 파일 없이 기본값 허용(개발 편의)
- main 기동 로그에 APP_ENV·설정 파일 명시
- 루트 compose: anchoring 서비스에 APP_ENV=local + config.local.toml 마운트
- config.toml.example 을 3환경 공용 템플릿으로 갱신, .gitignore 에 config.*.toml
(env별 실파일은 gitignore — dev/prod 는 배포 시 CHANGE_ME 채움)
- TODO.md 삭제(주요 과제 전부 종결) + README·개발용.md 참조 정리
- 검증: 모듈 20 테스트 통과, APP_ENV=staging fail-fast(exit 1)·local dry-run 기동 확인
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Dockerfile 의 COPY config.toml* 제거: 실 시크릿이 이미지 레이어에 구워지는 문제 해소
- .dockerignore 신설로 빌드 컨텍스트에서도 config.toml 차단(이중 방어)
- docker-compose 가 ./config.toml 을 읽기 전용 마운트 — up 전에 파일이 있어야 함
(없으면 docker 가 디렉터리를 생성해 기동 실패 — 주석·런북에 명시)
- 설정 변경 반영이 리빌드 없이 restart 로 단순화
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- 인수인계.md §1 에 적용 완료 블록(이식 위치·무Redis 계약·검증 결과·전환기 점프
확인 결과) 추가, 적용 순서 ③ 쿼리 컬럼명 오류 수정(anchor_rate_after →
뷰 실제 컬럼 anchor_rate_permille)
- 개발용.md §7(Redis)·§9.1 과 README 경계표의 "negodata 가 Redis 참조" 서술을
실제 적용 상태(current_rates 뷰 직조회)로 보정 — Redis 사용 주체는 배치만 남음
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- common/anchoring 이식 패키지 신설: 원본(schedules/anchoring)에서 읽기 경로 발췌
(constants·base_table·service) + reader 이식판(Redis 미사용 — current_rates 뷰
단일 쿼리, 실패·무이력 시 정적 테이블 폴백으로 견적 생성 무중단)
- _build_quotation: 목표가 산정과 앵커 산출 분리 — 칸(items.company_id ×
quotations.supplier_type × 가격구간) rate 로 tp*(1000-rate)//1000 정수 박제,
anchor_rate_permille 동시 기록. quotation_settings.anchoring_value 계산 사용 중단
- 재생성(regenerate_next_round): target_price 만 상속, 앵커는 생성 시점 rate 재계산
(인수인계 규칙 1 — 상속 폐지)
- sessions 모델 anchor_rate_permille 매핑, crud get_item_companies 신설
- 테스트 6종 신설(스키마 부재 폴백·칸별 조정 반영·유형 미지정·재생성 재계산·
bracket 경계 골든 벡터) — 전체 스위트 50 통과
- negodata 담당자 승인 하 직접 적용. 6개월 압축 시뮬레이션(격주 배치 13회,
세션 522건)으로 박제→소비→재박제 루프·클램프·이월·이중소비 방지 검증 완료
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- 04-alter 에 quotations.close_reason · quotation_settings.mid_action/over_action/regen_limit ALTER 누락분 append. 기존 DB 마이그레이션이 close_reason 개편을 안 담고 있어 UndefinedColumn 나던 것 보정(멱등 IF NOT EXISTS).
- postgres-init/01-schema.sql·04-alter.sql → *_20260702.sql 로 rename(스키마 최종 변경일 = 파일명). 사람들이 DB 최신 여부를 파일명으로 판단.
- 주석·문서 참조(README·docker-compose·02-learning·agent models·anchoring doc)는 글롭 01-schema*.sql·04-alter*.sql 로 바꿔 다음 rename 때 수정 불필요.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
종합 피드백에서 남긴 마지막 개선 3종:
- --once --dry-run: 판정·예상 조정(조정예정 라인)·제외 예정 건수를 로그로만
보고 DB/Redis 를 일절 변경하지 않는 예행 연습 — 첫 운영 실행(레거시 전량
판정·마킹) 전에 규모를 눈으로 확인하는 안전장치. status=dry_run, 종료코드 0
- 박제 정합 감시: 스캔 시 정수식 tp×(1000−rate)//1000 과 박제 anchor 를 대조,
불일치 시 WARN + 요약에 snapshot_mismatch — negodata 이식 오류(float 잔재·
칸 해석 오류)를 적용 첫 주에 자동 감지. 전환기(rate 미박제)엔 자동 스킵
- 전환기 점프 절차화: 인수인계 적용 순서에 "negodata 적용 직전 current_rates
분포 확인 → 점프 감수/이력 리셋 정책 결정" 단계 삽입 + TODO 등재
테스트 2종 추가(dry-run 무변경·정합 WARN) — 모듈 20개·backend 57개 통과.
리허설 완료: dry-run 예상과 실제 실행 결과 일치 확인(제외 3·조정 1칸 10‰→30‰).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
모듈·backend·문서 3개 관점의 적대 리뷰에서 확인된 결함 일괄 수정:
[모듈]
- 배치에 company_ids 스코프 옵션 추가 — 통합 테스트가 공유 dev DB 의 실세션을
소비/마킹하던 문제 해소(테스트는 시드 회사로 한정), 표적 수동 실행 옵션 겸용
- Redis 방어: compose 포트를 127.0.0.1 바인딩(무인증 공개 차단), get_rate 에
범위([10,200]) 검증 — 오염 캐시값은 미스 취급 후 자가 교정, 미스 백필은 SET NX
(배치가 방금 쓴 새 값을 구값으로 덮는 write-after-read 경합 방지)
- 배치: Redis ping 후 re-SET(다운 시 셀×timeout 지연 없이 즉시 스킵), 스캔 조인
ON 절에 quotations/items deleted 필터(철회 거래를 학습에서 배제), 제외 마킹을
청크별 커밋(레거시 대량 첫 실행의 장시간 단일 트랜잭션 방지)
- main: SIGTERM/SIGINT 핸들러(docker stop 시 정리 로직 보장), --once 부분 실패 시
종료코드 1(런북/cron 감지 가능)
[backend]
- finalize_session·update_last_offered_price 에 status=IN_PROGRESS 가드 —
negodata 일괄마감/중복 전송 경합이 종료된 세션을 되살리거나 가격 흔적을
사후 변경하는 것 차단(파생 판정 결정성 보호)
- 신규 DB 부트스트랩: sessions 3컬럼을 postgres-init/01-schema·04-alter 에도
반영(backend 가 모듈 DDL 없이 기동) — anchoring 스키마 자체는 모듈 소유 유지
- 낡은 주석 정리(agent_client·quotation_settings 의 구 앵커 산출 서술)
[테스트·문서]
- 신규 테스트: 격주 게이트 골든(ISO 주차), supplier_type NULL, 가격 제시율 0%
WARN — 모듈 18개·backend 57개 통과
- 문서 정합 감사 20건 반영: 잔존 33,334/노출 문구 제거, §10 SQL 을 실제 코드
(LEFT JOIN+deleted)와 일치, §11 자동/수동 검증 구분, FastAPI 오기 제거,
인수인계 reader 시그니처(db 인자), TODO 백로그 5건 기록
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
DB 과설정 점검에서 발견: 기존 술어(adjustment_id IS NULL AND deleted=false)로는
배치가 마킹하지 않는 비재협상 세션(재견적 등)이 인덱스에 영구 잔류해, "이월 풀만
담는 소형 인덱스" 의도와 달리 전체 세션 수에 비례해 성장하고 sessions 쓰기마다
유지 비용을 냈다. qt_type=1 을 술어에 포함해 재협상 미처리분만 남도록 수정
(키 컬럼도 status 단독으로 축소). dev DB 재생성 적용, 문서 동기화.
점검 결과 그 외 객체(테이블 1·컬럼·인덱스 1·뷰 2)는 과설정 없음으로 판정.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
요구(회사별 앵커링 값 업데이트 리스트업 + 이전 값 판별)는 rate_adjustments
한 행에 anchor_rate_before→after 가 박제되어 이미 충족 — 신규 테이블은 동일
정보의 사본만 만들므로 기각하고, 조회를 제품화하는 파생 뷰로 해결:
- anchoring.rate_history: 값 변경 이력 리스트업(이전→새 값, delta_permille,
success_rate, created_at)
- anchoring.current_rates: 칸별 현재값(최신 조정 행 — 없는 칸 = 시작값 10‰)
뷰는 상태가 없어 오염·재구축 이슈 자체가 없고 append-only 보호 대상 아님.
통합 테스트에 뷰 검증 추가(이력 before/after·성공률, 현재값). 운영 문서 §8
쿼리를 뷰 기반으로 단순화, TODO 과제 2 종결(대시보드 페이징 요구 시 스냅샷
테이블 승격 재검토 명시).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
균일 3,000원 × 33,334칸 → 자릿수 사다리 46칸. 폭 = 구간 상한의 10%
(선행 자릿수 밴드): [0, 1,000) 통일 1칸 + 자릿수(1천~1억, 5개)당 9칸
— "1천 원대·2천 원대 … 9천만 원대". 1억 초과는 마지막 인덱스(45) 클램프.
- 고가 구간의 무의미한 3,000원 해상도 제거 → 칸당 표본 밀도 대폭 개선
(희소 칸 이월 문제 구조적 완화), 정적 테이블 2MB → 3KB
- 사다리 단일 소스 = constants.UPPER_BOUNDS(생성식), json 은 기동 시 대조 검증
- calc_bracket_index: // 3000 → bisect_right (좌폐우개 경계 규약 동일 유지)
- 조정 이력 0건 시점 적용 — 인덱스 재매핑/마이그레이션 없음. DB 스키마 무변경
- 골든 테스트 재작성(경계·자릿수 진입·클램프) + 사다리 형태 검증 추가 — 16 passed
- 문서 5종·인수인계·README·스키마 주석 동기화, TODO 과제 1 완료 처리
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
두 과제 모두 정책 재확정 + 스펙 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>
처음 보는 운영/개발 담당자가 이 문서 하나로 따라할 수 있게 구성:
설치(스키마 적용→설정→도커/로컬 실행), 정상 동작 체크리스트(기동 로그 3줄,
--once), 로그 읽는 법(한 줄 해부·회차 흐름 표·grep 레시피·레벨별 대응),
자주 하는 운영 작업, 증상별 트러블슈팅 표, DB 이력 추적 쿼리 3종,
금지 사항, 격주 정기 점검 체크리스트. README 에 첫 방문자 안내 추가.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
장기 운영 관점 자체 점검에서 나온 6개 구멍 반영:
- 회차 추적: 모든 배치 라인에 [batch {run_id}] 태그 + 시작 로그(ISO 주차·force)
+ 상주 기동 시 다음 실행 예정 시각 출력
- 회사별 구분: 칸별 조정 상세(company= type= bracket= n= 성공= before‰→after‰
adj_id=)와 회사요약(테넌트당 1줄: 평가/상승/유지/하락/이월/실패/제외) —
grep company=<uuid> 로 테넌트 단위 추적, adj_id 로 DB 행 교차 확인
- 경보 연결: failed_cells>0 이면 종료 요약 WARNING 승격, Redis 실패는 연산별
처음 5건만 WARN 후 누계 요약(폭주 억제)
- 시간대: 로그 타임스탬프를 컨테이너 TZ 무관 KST(+0900) 고정, slim 컨테이너
zoneinfo 보장용 tzdata 의존 추가
- 스케줄 가시성: apscheduler 로거를 동일 핸들러에 연결(misfire 등 유실 방지)
- 로테이션: compose 에 json-file 10MB×5 설정(디스크 보호)
docs/개발용.md §8 로그 규약, README 로그 확인법 추가. 테스트에 로그 규약
검증(run_id 태그·조정 라인·회사요약) 포함 — 15 passed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- _resolve_anchor_price: quotation_settings.anchoring_value 스칼라 계산(float)
삭제 → 세션 생성 시 박제된 target_anchoring_price 를 그대로 사용(협상 중
불변). 박제 없으면 무할인 폴백(anchor=target)+WARN — 미박제라 집계 자동 제외
- 가격 입력 턴마다 sessions.last_offered_price 를 봇 메시지와 같은 트랜잭션으로
갱신(chat_crud.update_last_offered_price) — 앵커링 표본 판정의 "가격 흔적".
가격 쓰고 중간 이탈 → 일괄마감된 세션도 실패 표본으로 측정 가능
- sessions 모델에 anchor_rate_permille / last_offered_price /
anchoring_adjustment_id 3컬럼 추가 (DDL 은 schedules/anchoring/schema.sql 소유)
- e2e 테스트 2종(박제값 소비·제시가 기록 / NULL 폴백) — fake agent 더블
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
schedules/anchoring — backend 를 import 하지 않는 독립 컨테이너 배치 서비스.
회사 × 협력사유형(1유통/2제조/3총판) × 가격구간(3,000원, 33,334칸)별 앵커링
값(정수 천분율)을 격주 토 00:00 KST 에 협상 성공률로 자동 조정한다.
- 판정 = "가격 흔적" 기준: last_offered_price 가 있는 종료 재협상만 표본,
DONE & bid ≤ 박제 앵커만 성공, 나머지(초과 합의·결렬·가격 쓰고 이탈) 실패.
앵커는 비노출(엔진 내부 체결 임계) — agent 무변경
- 저장 = anchoring.rate_adjustments 1개(append-only, consumed_session_ids 박제),
소비 경계 = sessions.anchoring_adjustment_id 마킹(멱등·이월). DDL 은 모듈
소유(schema.sql, sessions 3컬럼 ALTER 포함)
- 안정성: 조정 INSERT+마킹 한 트랜잭션 + rowcount 불일치 전체 롤백,
Redis TTL 7일 + 매주 조정 칸 re-SET, socket timeout 0.3s, DB 폴백,
가격 제시율 0% WARN, --once 수동 캐치업
- 정적 기본 테이블(전 구간 10‰, 상한 정확히 1억·초과분 마지막 인덱스 클램프)
기동 검증 실패 시 기동 중단
- 전체 async(SQLAlchemy+asyncpg, redis.asyncio) — negodata 가 reader 를 그대로
이식 가능(docs/인수인계.md). 최종 문서 docs/{개발용,기획용,워크플로우}.md
- 테스트 15종: 골든 벡터(§11) + DB 통합(멱등·이월·격리·rowcount 롤백)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- 동적 가중치 W: 라운드 감쇠 → 상태 5차원 가중합 clip(Σwᵢ·Sᵢ, 0.2, 0.8) (식 12~13, 기존 w1~w5 연결)
- 종료보상에 (1−W) 적용: R = W×R_price + (1−W)×R_end − λ×round (식 8)
- R_price 3단계: P<anchor 시 1+β·(anchor−P)/anchor 초과달성 보너스 추가 (식 9~11, beta 의미 재정의)
- price zone 경계는 명세(T)와 달리 anchor 유지(우선협상 규칙이 실제 의사결정 경계) — 사유 docstring 명시
- state_calculator/config 의 낡은 반대 컨벤션(anchor≥target) 주석 정정
- RewardCalculator(RewardConfig, StateConfig) 시그니처 변경 + 호출부 5곳 갱신, 테스트 기대값 정정 (76/76 PASS)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- test DB 세션마다 자동 create/drop (팀원은 Postgres만 있으면 pytest 한 방)
- auth_headers 시드 픽스처(무인증 /auth/create 제거 대응) + other_company_id
- 커버: 회사 스코프(견적·상품·협력사·대시보드·세팅), 견적 마감 재견적 O/X + 알림,
견적 생성·목표가, 알림함 읽기, 회사유저 OWNER 게이팅, 기존 파일 검증/기대결과 주석 정비
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- 견적 생성: 협력사 유형 전 유형 입력(항상 노출), 명칭 협상견적→견적, 단계 인디케이터 확대·클릭 이동, 라벨 통일
- 온보딩 가이드: 견적 유형 차이 안내 탭(목표가 산정·협력사 수, MD 제시가 우선 강조)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
quotations 에 company_id 컬럼이 없어 견적 조회가 회사 무관하게 전부 노출되던 멀티테넌트 누수를 차단. 작성자(user_id)→users.company_id 서브쿼리로 회사 스코프를 걸어 목록(/list)과 단건·세션·협력사 엔드포인트(_fetch 가드)에서 남의 회사 견적을 NOT_FOUND 처리. 스케줄러/내부 호출은 company_id 없이 우회. 라우터/서비스의 '회사 스코핑 안 함' 거짓 주석 정정.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- 생성(_calc_target_price)과 표시(get_target_breakdown)가 _candidates 헬퍼를 공유
→ 프론트 재계산 제거, 저장된 목표가와 항상 일치
- TargetPriceModal: useGetTargetBreakdown 으로 후보·채택·앵커링가 '표시만'
- QuotationType.is_new() 한 곳에서 신규유형 판단(생성·산정 공통)
- enum 라벨 단일출처(lib/enumLabels.ts): 협력사유형/카드 사용구분/유저상태
members·CardFormSheet 는 거기서 re-export
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
[견적·목표가]
- 목표가 산정 KTC 기준 정비(MD 우선, 없으면 인터넷최저가·매입가·판매가 중 최저 / 신규는 인터넷최저가만)
- 인터넷 평균 수수료 0.078 상수화(견적설정 컬럼 제거)
- 앵커링가 세션 저장 + 목표가 클릭 시 산정내역 모달
- 재생성 시 목표가·앵커링가 재계산 없이 직전 값 상속(KTC)
- MD 제시가·협력사 유형(유통·제조·총판·기타) 입력
[협상카드]
- 사용 구분(공통/신규견적전용/재견적전용)
[협상 진행]
- 협력사 초청 메일 발송(일괄/개별·재발송, 발송상태 표시)
[기타]
- 견적상세 창 닫기 버그 수정, 불필요한 컬럼 주석 정리
- DB: 기존 DB는 postgres-init/04-alter.sql 적용 필요(자동 마이그레이션 없음)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- OWNER 권한 신설, 최고관리자가 자기 회사 소속 직원(USER) 계정 생성·수정·삭제 관리
- 회사 사용자 API(/v1/company/user/*), 회원관리 페이지·폼
- 로그인/프로필 흐름 정비, 무인증 계정생성(/auth/create) 제거
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
postgres-migrations/ 폴더(날짜파일) 접고 postgres-init/04-alter.sql 한 파일로.
negodata 는 마이그레이션 러너가 없고 수동 psql 이라, IF NOT EXISTS 로 재실행 안전한
단일 alter 파일에 앞으로 변경을 append 하는 방식이 단순. 04-alter-negodata-pricing → 04-alter.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
postgres-init/ 는 신규 DB 부트스트랩(01 schema·02 learning·03 seed) 전용이라
ALTER(기존 DB 대상)는 별도 디렉터리로 분리. 앞으로 마이그레이션은
postgres-migrations/YYYY-MM-DD-설명.sql 로 추가한다.
04-alter-negodata-pricing.sql → 2026-06-26-pricing-classification.sql
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- models.py: created_at/updated_at/last_accessed_at/start_time/end_time/bid_at
DateTime → DateTime(timezone=True)
- quotation_service: tz-aware 입력을 naive 로 깎던 _naive_utc 제거(컬럼이 tz-aware라 불필요),
start_time/end_time 직접 사용. negosium_db 는 UTC 고정.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
백엔드 close_and_decide 경로:
- 동시 이중 마감 가드: 마감 판정 전 원자적 CLOSED 선점(claim)으로 두 크론 잡·수동마감 경합 직렬화
- 재생성 실패 표면화: regenerate_next_round 결과 검사 → 실패 시 REGEN_FAILED 반환(체인 끊김 은폐 방지)
- 차수 충돌 방지: 다음 라운드 = 체인 최신 round+1(chain_max_round 기준)
- 재생성 사유 집계 정밀화: 미참여/동가를 양성 표식으로 구분(단독낙찰·거부 오집계 제거)
- 재생성 라운드 최소 협상기간 하한(즉시 재마감 캐스케이드 방지)
- 잡 루프 per-item 예외 격리(한 건 실패가 배치 전체를 멈추지 않음)
프론트:
- useChatController: 무권한 가드를 sessionId 별로 추적해 세션 변경 시 자연 해제
- useScrollLock: 마지막 해제를 rAF 로 지연해 재마운트 사이 일시적 잠금 해제 방지
- quotation 상세 쿼리 placeholderData 로 라운드 전환 중 시트 유지
테스트:
- 신규 test_close_and_decide_fixes.py(동시성·차수·집계·기간 하한 검증)
- conftest 결함 수정(존재하지 않는 tbl_account TRUNCATE 제거, companies.status 명시)
- stale 테스트 갱신(test_quotation_create 를 타입드 Req/신규 응답 형식에 맞게 재작성)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>