목차 › 8. 테스트
테스트
사람 승인 게이트를 없앤 대신 CI 를 안전망으로 세웠다 — 자동 5잡 · 백엔드 pytest 1,165건 · QA 시나리오 34개 · 최종 갱신 2026. 09. 22.
a6501231. 테스트 계획
이 프로젝트에는 사람 리뷰 게이트가 없다. 2026. 08. 28. 개정으로 사전 확인을 없앴고, 09. 04.부터는 브랜치 → PR → 자체 머지다 — 승인자가 없고 자기 PR 을 자기가 머지한다. 그리고 main 머지 = 2분 후 프로덕션 배포(서버 systemd timer 자동 CD)다. 사람이 빠진 자리에 무엇을 놓을지가 이 장의 전제였고, 답은 CI 초록 하나였다. 규약에 그대로 적혀 있다 — "CI 빨간불인 PR 은 머지하지 않는다. main 이 빨간불이면 다른 작업보다 우선 수정."
계기는 사고다. 2026. 09. 01. 하루에 깨진 main 을 두 번 발견했고 둘 다 우연이었다
(d7fdd10 · d96749e). 그래서 CI 를 넣을 때의 목적을
"게이트"가 아니라 "깨졌다는 사실만 즉시 보이게"로 잡았다 —
우정 B 가 09. 02. 게이트(09. 04.)를 앞두고 먼저 올렸고,
파일 소유는 인프라 도메인이라 사후 공지로 처리했다.
코드를 바꿨으면 해당 파트의 실행/테스트를 돌리고, 결과를 커밋 메시지에 한 줄 남긴다. 리뷰어가 없으므로 이력이 곧 기록이다.
테스트를 통과시키려고 주석 처리하거나 우회하지 않는다. 실패하면 실패한 대로 커밋 메시지와 팀 채널에 적는다. 초록을 만드는 것이 목적이 아니라 상태를 아는 것이 목적이기 때문이다.
발견한 사람이 고치거나(fix-forward) revert 한다. 2분 뒤 배포되므로 합의를 기다리는 시간이 곧 장애 시간이다.
층위 — 무엇을 어느 시점에 재는가
| 층위 | 대상 | 도구 | 시점 | 실측 |
|---|---|---|---|---|
| 백엔드 린트 | 미정의 이름 · 미사용 import | ruff check --select F |
push · PR | 배포 후 500 의 주원인을 1초에 잡는다 |
| 백엔드 단위 · API | 실제 PostgreSQL + pgvector 에 alembic 이행 후 실행 | pytest + pytest-timeout(60초) |
push · PR | 1,165건 통과 |
| 프론트 | 타입 · 린트 · 빌드 | oxlint + tsc -b + vite build |
push · PR | 테스트가 없어 빌드가 회귀 그물 |
| 앱 | 위젯 · API 클라이언트 | flutter analyze + flutter test |
push · PR | 파일 30개 · 373건 |
| AI 면접 서버 | 실시간 전사 · 판정 중계 · 화자 매칭 | pytest (Python 3.13) |
push · PR | 110건 / 50초 |
| 에이전트 회귀 하네스 | 실서버 /agent/chat 시나리오 — 정답 · 속도 · 창작 여부 |
자체 하네스 (-m regression) |
모델 · 프롬프트 변경 시 | 55건 (10 + 30 + 15) |
| 계약 대조 | 배포본 OpenAPI ↔ main 경로 · 스키마 · 인증 | check_public_contract.py |
배포 후 | 09. 02. 경로 55/55 · 스키마 75/75 |
| 스키마 대조 | alembic 이행 결과 ↔ 모델 | check_schema_drift.py |
pytest 직전 (CI) | 이행 누락 2건을 잡아낸 뒤 상설화 |
| 모델 채점 | 동일 케이스 23건을 같은 자로 — 도구 이름 · no-tool 위반 · 확인 문구 · 인자 · 응답 | judge.py |
모델 · 어댑터 비교 시 | 학습 전 Qwen 26.1% · Claude Haiku 69.6% · Qwen v9 73.9% |
| E2E · QA | 필수 27기능 시나리오 (전제 → 절차 → 기대) | qa-scenarios 문서 | 게이트 판정 | 09. 04. 1차 게이트 4항목 충족 · 09. 30. 2차 예정 |
안 한 것도 적는다. 프론트엔드에는 테스트 코드가 없다 — tsc -b 가
사실상의 회귀 그물이고, 그 이상은 남은 기간에 넣지 않기로 했다. AI 면접 서버에도 린트를
아직 붙이지 않았다: 기존 오류 5건(analyze_file · app ·
deception_vit · interview_ws ·
test_interview_ws)이 남아 있어 지금 붙이면 아무도 안 보는 빨간 CI 가
되기 때문이다. 다음 ai/ 변경 때 정리한 뒤 붙인다.
2. 단위 및 통합 테스트
CI(.github/workflows/ci.yml)는 잡 5개다. 같은 브랜치에 연달아 push 하면
앞의 실행을 취소한다(concurrency + cancel-in-progress) —
무료 러너 분을 아끼기 위해서다. 아래 표의 칩은 그 잡을 실제로 올린 사람이다 —
파일 자체는 인프라 도메인이라, 남이 올린 경우는 사후 공지로 처리했다.
| 잡 | 하는 일 | 들어온 계기 | 추가 |
|---|---|---|---|
| lint 수택 E |
uvx ruff@0.16.7 check --select F app tests |
헥사고날 이동 뒤 NameError 2건이 프로덕션까지 갔다 —
schedules.py 의 timedelta 미import,
assignments.py 의 함수 밖 PgTalentRepository.
둘 다 그 줄을 타는 테스트가 없어 pytest 초록, 배포 뒤 500 |
09. 12. |
| backend 우정 B |
uv sync --frozen → pgvector 확장 →
alembic upgrade head → 모델↔이행 비교 →
pytest -q |
깨진 main 을 하루 두 번 우연히 발견 | 09. 02. |
| frontend 우정 B |
npm ci → oxlint → tsc -b + vite build (Node 22) |
같음 — 백엔드 잡과 같은 커밋으로 첫 CI 에 함께 들어왔다 | 09. 02. |
| ai 수택 E |
apt 5개(opencv · mediapipe · soundfile) 후
pytest 3파일 |
실시간 면접 서버 시험 110개가 CI 밖에 있었다. 09. 01. 이후 51번 바뀌었는데 매번 각자 로컬 컨테이너로만 확인했다 — 깨졌는지가 머지한 사람의 기억에 달려 있었다. 우정 B 가 로컬에서 110 passed / 50초를 실측한 뒤 요청했다 | 09. 17. |
| mobile 수택 E |
Flutter 3.44.8 — flutter analyze + flutter test |
09. 15. 앱 시험 15건이 깨진 채 며칠 지나갔다 — 아무도 몰랐다. Issue #254 — 민아 C 원안 | 09. 17. |
백엔드 — 목 DB 를 안 쓴다
테스트 DB 를 흉내로 대체하지 않았다. CI 는 pgvector/pgvector:pg16 서비스
컨테이너를 띄운다 — 순정 postgres 를 쓰면 vector 확장이 없어
conftest 가 application_embeddings 를 건너뛰고, 그러면 임베딩
경로가 CI 에서 통째로 안 돈다. 로컬 docker-compose 와 같은 이미지를 쓰는 이유가 그것이다.
격리는 트랜잭션으로 한다 — db fixture 가 각 테스트를 트랜잭션으로 감싸고
끝나면 롤백해서 DB 에 흔적이 남지 않는다.
파일 52개에 def test_ 가 1,084개이고, parametrize 확장까지 포함해
1,165건이 통과한다(커밋 a650123 — 같은 실행에서 55건은 skip,
그 로컬에 pgvector 가 없어서다). 09. 02. 실측 기준으로는 486건에
CI 14.5초 · 로컬 88.6초였다 — 로컬이 느린 것은 WSL 이
/mnt/c 를 읽는 속도 탓이지 테스트 탓이 아니다. 백엔드 로드맵의 W5 완료
기준("uv run pytest 30초 내")은 러너에서는 이미 만족한다.
CI 가 잡은 것 — pytest 만으로는 안 보이던 두 종류
check_schema_drift.py (09. 17.)
alembic upgrade head 스텝만 있으면 초록이 거짓이 된다.
pytest 의 conftest 가 create_all 로 이행에 빠진 표를
채워 넣기 때문이다. 실제로 두 번 그랬다 — 09. 16. email_logs.stage 의
password_setup 을 모델에만 넣어 운영에서 메일 행 INSERT 가 거부됐고,
09. 17. 이행 번호 0023 중복(#282)으로 운영 DB 에 file_blobs 가
안 생길 뻔했다. 그래서 이행 직후 · pytest 전에 표 · 컬럼 ·
NULL 허용 · CHECK 허용값 · UNIQUE · 인덱스 이름 다섯 가지를 비교하고,
다르면 종료 코드 1 이다. 번호 중복 자체는 별도로
tests/test_alembic_revisions.py 가 막는다 — DB 없이 파일만 읽고,
번호를 짓는 사람이 둘 이상이면 언제든 다시 나기 때문이다.
conftest.py 의 스위치 선점
개발자 .env 에만 있는 키가 판정을 갈랐다. ANTHROPIC_API_KEY 가
있으면 백엔드가 "사용 가능"으로 보이지만 CI 에는 없어 503 으로 갈린다 — 이 갈림으로
실제 사고가 났고 d4580e2 로 사후 복구했다. 그래서 conftest 가
알려진 스위치 12개를 빈 값으로 선점하고 COMPANY_NAME 은
CI 의 실효값 "Arda" 로 못 박는다. 지우는 것으로는 안 된다 —
app/main.py 의 load_dotenv() 가
없는 키에는 .env 값을 넣기 때문에, 미리 값을 잡아두는 것이
유일하게 확실한 방법이다.
09. 04. 로컬에서 Docker Desktop 이 죽어 DB connect 대기로 pytest 가 24분간 조용히 멈췄다. 침묵을 실패로 바꿨다 — 타임아웃이 걸리면 어떤 테스트가 어디서 기다렸는지 스택과 함께 드러난다.
회귀 하네스 — 기본 스위트 밖에 둔 이유
소연 D 도메인의 에이전트는 "되냐"가 아니라 "얼마나 잘 되냐"를
재야 한다. 그래서 backend/tests/prompt_regression/ 는 실 백엔드
(localhost:8000)에 실호출하고, @pytest.mark.regression 이
붙어 기본 pytest -q 에서 자동으로 제외된다 —
시나리오 하나당 5~40초라 CI 기본 스위트에 끼면 매 PR 이 몇 분씩 밀린다.
-m regression 을 명시해야만 돈다.
| 세트 | 건수 | 재는 것 | 기준 |
|---|---|---|---|
test_step0 |
10 | 인사 · 자기소개 · 목록 · 이름 검색 · 역량 검색 · 단계 변경 요청 등 정형 문장 | Ollama qwen3:4b · Guard 도입 후 10/10 · 평균 15초가 회귀 기준선 |
test_intent_variations |
30 | 존칭(씨 · 님) · 오타 · 존댓말 · 조사 변형 — 정형 10개는 regex 가 잡게 만든 것이라 진짜 정확도는 변형에서 드러난다 | 의도 정확도 wrong ≤ 5% · p50 ≤ 4s |
test_faq |
15 | 지원자용 공개 챗 — 공고 정보 · 본인 상태 응답, 차단 주제(연봉 · 합격 가능성 · 다른 지원자) 거절, 프롬프트 주입 방어 | 거절 문구로 답하고 주입에 넘어가지 않을 것 |
하네스의 assert 는 최소한만 건다. 대신 구조적 기준 두 가지는 깨지면
채택 불가로 못 박았다 — ① 렌더된 답변에 시드 밖 이름이 없어야 한다(도구 결과
창작 차단) ② change_stage 확인 카드는 기대한 지원자를 가리켜야 한다
(다른 레코드 차단). 성공률 · 응답 시간은 results/*.jsonl 에 append 로
쌓여, 프롬프트를 고친 뒤 다시 돌리면 같은 파일의 diff 로 개선이 보인다.
쓰기 의도는 확인 카드까지만 만들고 실행하지 않으므로 하네스가 DB 를 바꾸지 않는다.
계약과 구조도 스크립트로 잰다
check_public_contract.py 는 배포본 /openapi.json 에서 GET 을 전부
뽑아 토큰 없이 한 번씩 때려 본다. 경로 목록을 코드에 박지 않은 이유는 명시적이다
— 박아두면 새로 생긴 엔드포인트가 대조에서 빠져 무의미해진다. 경로 변수에는
존재하지 않는 값을 넣어 실지원자 데이터에 닿지 않고, 읽기만 한다.
실측은 08. 31. 경로 35/35 · 스키마 62/62, 09. 02. 경로 55/55 · 스키마 75/75
· 필드 불일치 0 이다.
check_architecture.py 는 ADR-0035 헥사고날 적용 상태를 AST 로 센다.
이유를 스크립트가 직접 적고 있다 — "포트 · 어댑터로 바꿨다"는 말은 폴더를
만든 것만으로도 참이 되어 버린다. 2026. 09. 12. 실측값을 기준선으로 박아
--strict 는 원시 DB 접근이 늘면 실패한다. 그때 판정은
"구조는 갖췄지만 실질은 절반"이었고, 그 숫자를 남겨 뒀다.
3. 사용자 인수 테스트
인수 기준은 docs/00_overview/qa-scenarios.md 한 곳이다. 2026. 08. 24. 작성했고,
그 시점에 화면이 아직 없어서 05-design 의 화면 지도를 기준으로 썼다 —
확정되지 않은 UI 디테일은 "(화면 확정 후 갱신)" 으로 표시해 둔다.
각 시나리오는 전제 → 절차 → 기대 결과 세 줄이다: 어떤 상태에서,
누가 무엇을 클릭 · 입력하고, 무엇이 보이면 성공인가.
| 군 | 건수 | 담는 것 |
|---|---|---|
| A. 인증 · 권한 | 3 | JWT 가입 · 로그인, 역할 2종(관리자 · 멤버), 조작 제어 |
| B. 채용 공고 | 3 | 생성 · 수정 · 삭제, 상태 3종, 공고별 지원자 수 집계 |
| C. 지원 (로그인 없음) | 3 | 공개 링크 지원서 제출, 이력서 업로드, 개인정보 수집 동의 |
| D. 지원자 관리 | 6 | 테이블 · 칸반 · 드래그 단계 이동 · 상세 · 단계 이력 · 담당자 직접 등록 |
| E. 평가 | 2 | 점수(1~5) + 코멘트 작성, 목록 조회와 평균 점수 |
| F. 파일 | 2 | presigned URL 로 브라우저 → S3 직행 업로드, 다운로드 |
| G. 알림 · 메일 | 3 | 단계 변경 메일, 비동기 처리(200ms 내 응답), 실패 시 재시도 |
| H. 검색 · 필터 | 2 | 이름 · 이메일 검색, 단계별 필터 |
| J. 시스템 · 운영 | 3 | Docker 구성, AWS 배포, Swagger /docs |
| 실패 케이스 | 7 | 중복 지원(409) · 허용 안 되는 형식 · 용량 초과 · 권한 없는 접근(403) · 마감 공고 지원 · 로그인 실패 · 필수 항목 미입력 |
시나리오는 결정이 바뀌면 같이 고친다. A3 "면접관은 배정된 지원자만 조회"는 08. 31. ADR-0017(등급 이분화)로 폐지됐고, 확인할 것이 "무엇이 열렸는가 · 무엇이 남았는가"로 바뀌어 세 갈래로 쪼갰다 — A3-1 조회는 전원 열려 있다(미배정 10명 포함 12명 전원이 보인다), A3-2 멤버는 배정된 건만 평가를 쓴다(그 외 403), A3-3 면접관 배정 · 남의 가용 시간은 관리자만(단 본인 가용 시간은 멤버도 가능). 시나리오가 낡은 채 남아 있으면 인수 기준이 아니라 오해의 근거가 된다.
1차 게이트 (09. 04.) — 09. 02. 수직 슬라이스 실측
게이트 판정은 문장이 아니라 실데이터 한 번 관통으로 했다. 공개 지원 폼 제출 →
DB 저장 → 담당자 확인까지다. 게이트 4항목 중 마지막까지 미충족이던 것이 이
수직 슬라이스였고, 판정일(09. 04.)보다 이틀 앞선 09. 02.에 관통해 닫았다 —
코드 변경 없이 브라우저로 실제 경로를 한 번 통과한 것이다. 기존 공고를 쓰지 않고
검증용 공고(id 3)를 새로 만들어 관통한 뒤 closed 로 내렸다:
C6 의 UNIQUE(job_posting_id, email) 에 걸릴 수 있고, 공개 링크 발급이
재발급이라 그 공고의 기존 토큰을 즉시 무효화하기 때문이다.
| 단계 | 결과 |
|---|---|
| 공개 링크로 공고 조회 (로그인 없음) | 통과 GET /public/postings/by-token/{token} |
| 이력서 PDF 첨부 → 브라우저에서 S3 직행 PUT | 통과 |
| 제출 | 통과 지원자 id 24 ·
source=form · files 1행 |
| 담당자 화면 표시 | 통과 목록 · 상세 모두 |
| 접수 확인 메일 | sent 기존 15건이 failed 인 것과 달리 성공 |
| 단계 이력 | (없음) → applied |
| 담당자의 첨부 열람 | 통과 실측 시점엔 받아보는 쪽 화면이 없었고,
프론트 오너에게 넘겨 같은 날 f4d7a1b 로 닫혔다 —
826 B PDF 원문이 그대로 렌더 |
검증 방법 자체를 기록으로 남겼다. 첨부를 눌러도 브라우저에서 아무 일이 없어 보일 수
있는데, 그것이 기능 실패인지 환경 탓인지 구분하려면 같은 URL 을 iframe 으로 불러 렌더되는지
본다(iframe 로드는 CORS 검사를 안 받는다). 오류 표시와 콘솔이 비어 있는데 화면만 안 바뀌면
환경 쪽이다. 실제로 버킷 CORS 의 AllowedMethods 가 PUT 뿐이라
브라우저 fetch GET 은 막히고, 이 판별법 없이는 서버가 멀쩡하고 로그에도 안 남는
함정에 다시 빠진다.
2차 게이트 (09. 30.) — 아직 안 돌았다
조건은 필수 27개 기능 전부 프로덕션 동작 · 에이전트와 앱도 데모 가능 · QA 시나리오 전 항목 통합 리허설 2회 · 09. 28.~30. 전 도메인 공통 버퍼(코드 프리즈와 잔여 버그)다. 통합 리허설은 W5(09. 21.~25.)에 프로덕션 URL 과 실기기에서 도는 일정이고, 09. 22. 현재 아직 수행 전이다 예정.
외부 인수 — 멘토링이 실질적인 수용 심사였다
내부 QA 와 별개로 IBM 강사 멘토링이 사실상의 인수 창구였다. 09. 10. 멘토가
21개 항목을 짚었고(서류 · AI 요약 6 · 면접 7 · 지원자 쪽 4 ·
화면 · 앱 · 학습 4), 팀이 항목마다 현황과 대조해 "이미 동작 / 결정 필요 /
실측 필요"로 갈랐다. 09. 11. 숙제는 "지원자 · 관리자 입장에서 각각 시연 가능하도록
준비"였다 — 두 역할로 갈라 시연한다는 인수 기준이 여기서 나왔다.
09. 18. 피드백의 "모델 비교를 정량적으로"는 09. 22. 같은 채점기 기반 정량 보고서로
반영됐다 — 같은 날짜의 나머지 세 항목은 트래커에서 아직 doing 이다.
4. 결함 추적 및 조치
추적 창구는 셋이다. 하나는 GitHub 이슈 · PR, 하나는 피드백 트래커, 하나는 사람이 아니라 기계다.
리뷰 게이트가 없으므로 브랜치 · 커밋 메시지 · PR 본문이 전부 사후 참고
대상이다. 09. 22. 기준 main 의 커밋 1,095개 ·
머지된 PR 236건(번호는 #354 까지).
커밋 제목에는 기능 번호(D3 · G1 · J7)나 도메인 접두어를 붙이고,
type 은 feat fix docs test
chore refactor 다.
_data/feedback/<GitHub 아이디>.yml
멘토링 · 강의 피드백은 반영 담당자가 자기 파일에 적는다 —
칸반과 같은 원칙(한 사람 = 파일 하나)이라 git 충돌이 없다. 접수 시점에는
received · from · content ·
status: todo 만 채우고, 반영이 끝나면 같은 항목에
fixed · fix 를 채워 done 으로 바꾼다 —
접수와 반영이 한 줄에서 추적된다.
서버 안의 지표는 "서버가 살아 있다"까지만 안다. DNS · TLS · Caddy · 보안그룹이 죽어 밖에서만 안 되는 경우는 못 잡는다. 그래서 GitHub 러너가 15분마다 공개 주소를 사용자와 같은 경로로 부르고, 실패하면 이슈를 열거나 열린 이슈에 코멘트, 복구되면 "복구됨"을 달고 닫는다. 열린 이슈는 항상 최대 하나다. 공개 저장소라 비용 0.
도메인 밖 결함은 고치지 않고 넘긴다
다른 도메인에서 문제를 발견하면 직접 고치지 않고 이슈로 오너에게 넘긴다.
실례 — 백엔드가 앱 쪽 프레임 전송 문제를 09. 16.에 이슈 #260 으로 넘기면서
PR #154 를 닫고 살아 있는 항목 둘만 추렸다. 같은 건에서
"얼굴 114/114 no_face" 추적은 앱이 안 보내는 것과 서버가 못 찾는 것을
가르려면 양쪽을 같이 봐야 해서 서버 로그 대조를 백엔드가 맡기로 나눴다.
경계를 넘는 수정보다 경계를 넘는 정보 교환이 싸다.
사고 하나에 장치 하나 — 재발 방지 규칙으로 승격된 것
깨진 main 을 하루 두 번, 둘 다 우연히 발견
장치 — CI 도입. 이후 09. 04. 브랜치 → PR → 자체 머지로 main 에 닿는 경로를 하나로 좁혔다. 지금 5개 잡이 push · PR 마다 돈다.
미정의 이름 2건이 프로덕션 500
장치 — CI ruff --select F. 스타일 규칙까지 켜지 않은 것이
핵심이다 — 기존 파일 수백 줄이 빨개지면 아무도 안 보는 빨간 CI 가 된다.
잡는 것은 실제로 터지는 것뿐.
Docker 가 죽어 pytest 가 24분간 침묵
장치 — pytest-timeout 60초. 멈춤을 침묵이 아니라 실패로 바꿨다.
디스크 고갈로 배포가 죽음
장치 — 컨테이너 로그 상한 20MB×3 · 배포 때 이미지 · 캐시 prune · EBS 29 → 50GB(09. 10.). 이 건과 위 두 장치(멈춤 · 미정의 이름)를 묶어 세 부류 모두 재발 0 이다.
n8n 이 웹훅은 받고 죽어 메일이 queued 로 잔류
장치 — API 가 스스로 5분마다 밀린 메일을 SMTP 로 재발송(최대 3회, 초과는
failed 로 접어 사람이 확인). 합격 · 불합격 통보가 통째로 멎던
단일 장애점을 없앴다.
.env 를 고쳤는데 반영이 안 됨
장치 — docker compose restart 는 env_file 을 다시
읽지 않는다. up -d --force-recreate 를 규칙으로 문서화했다.
대조가 잡아낸 결함, 실측이 뒤집은 판정
| 결함 | 어떻게 드러났나 | 조치 |
|---|---|---|
| #59 면접관이 공고 수정 가능 #97 draft 공고 무인증 노출 |
무인증 GET 대조 — 지금까지 나온 권한 결함이 전부 이 대조에서 나왔다 | 대조를 스크립트로 굳혀(check_public_contract.py) 엔드포인트가 늘 때마다
자동으로 대상이 되게 했다 |
#282 이행 번호 0023 중복#283 file_blobs 누락 |
운영에만 표가 없는데 CI 는 초록 — create_all 이 가렸다 |
모델↔이행 비교를 CI 상설 스텝으로. 09. 22. DB 권한 분리 이후에는 누락이 곧 기동 실패라 더 중요해졌다 |
| 요건 우수 지원자가 우대 부족만으로 탈락 | fit-check 지원자 24명 3축 점수 실측 — 인수인계의 "자동 불합격 3명"이 실제로는 8명이었다 | PR #182 — 가중치 요건 50→60 · 우대 20→10 · 문화 30 유지 + 요건 ≥70 이면 문화 하한 50 |
| 자료가 없는 지원자를 채점하려 함 | 자소서 1줄 · 전부 미기재인 지원자가 판정 없이 남거나 사유 불명 「불합격」으로 보였다 | PR #349 · #351 — 요약 insufficient=true 면
「서류 탈락」 라벨로. false 인 지원자는 안 건드려 대량 탈락 방지 |
| AI 추정값이 신고값처럼 보임 | 폼에 경력을 안 적으면 AI 가 이력서에서 연차를 추출하는데 표식이 없어 구별 불가 (공정성) | career_years_source="ai" 표식 → 프론트 「AI 추정」 배지.
재생성 시 표식이 사라지는 문제는 PR #311 로 후속 — 09. 22. 현재 미머지 |
| 인터뷰방 답변 저장 실패 · 서류 대조 · CONFLICT 409 | 09. 10. 멘토링 21항목 점검 + 시연 리허설 중 실측 (Q9 시도 후 Q1 로 되돌아감) | PR #174 · #175 · #178 로 해결, PR #183 으로 Qwen 학습 파이프라인 착수 |
닫지 못한 것
안 된 것은 안 됐다고 적는다. 09. 15. 세션 75 에서 CPU 전사가 180초 상한을 넘겨
답변이 [전사 지연] 자리표시자로 저장됐다. 전사 속도 자체는 OpenAI API 전환으로
풀렸지만 이미 자리표시자로 남은 답변을 되살리는 경로는 없다
미해결 — 기능 미비가 아니라 지원자 데이터
손실이라 백엔드 큐 23번으로 남은 기간 맨 위에 뒀다. AI 면접 서버 린트 5건도 아직
CI 에 안 붙어 있다 대기.
이 둘은 초록을 만들어 가리지 않고 빨간 채로 문서에 남긴다 — 그것이
"테스트를 통과시키려고 우회하지 않는다"는 규칙의 실제 모습이다.