- src/dist 산출물 분리 원칙 정리(.gitignore, .gitattributes) - 루트 및 주요 폴더(config/scripts/prompts/tests/src, 런타임 폴더 5종)에 안내용 README.md 추가 - CHANGELOG.md, LICENSE, docs/ops/05-release-and-versioning.md 추가 - docs/README.md 문서 지도 갱신
433 lines
22 KiB
Markdown
433 lines
22 KiB
Markdown
# DMF Crawler TDD · E2E RED · 디자인 감사 운영 체계
|
||
|
||
> 이 문서는 DMF Crawler 의 **TDD/RED 운영 SSOT** 다.
|
||
> 이론 근거는 `docs/research/11-tdd-red-and-design-audit-theory.md` 를 따른다.
|
||
|
||
**상태**: v1 확정
|
||
**적용 시점**: 이 문서가 생성된 뒤의 모든 코드·GUI·리포트·에이전트 작업
|
||
**핵심 명령**: **테스트 없이 새 코드를 쓰지 않는다. RED 실패를 먼저 본다.**
|
||
|
||
---
|
||
|
||
## 1. 법칙
|
||
|
||
### 1.1 신성한 루프
|
||
|
||
모든 구현 작업은 다음 순서를 따른다.
|
||
|
||
1. **RED** — 실패하는 자동화 테스트를 먼저 만든다.
|
||
2. **RED 확인** — 그 테스트가 실제로 실패하며, 실패 이유가 기대한 요구 위반인지 확인한다.
|
||
3. **GREEN** — 통과에 필요한 최소 구현만 한다.
|
||
4. **REFACTOR** — 전체 관련 테스트가 Green 인 상태에서만 구조·중복·이름·디자인을 정리한다.
|
||
5. **REGRESSION** — 영향 테스트 + 전체 smoke 를 돌리고 결과를 기록한다.
|
||
|
||
### 1.2 금지
|
||
|
||
- 테스트가 없는 `src/` 기능 구현 금지.
|
||
- 실패를 보지 않은 테스트를 “RED” 라고 부르기 금지.
|
||
- 테스트를 약하게 바꿔 Green 만들기 금지.
|
||
- `pytest.skip`, `xfail`, 느슨한 `except Exception: pass`, `assert True` 류로 실패 숨기기 금지.
|
||
- 실패 중에 리팩터링 금지.
|
||
- 의미 없는 테스트를 무한히 추가하기 금지.
|
||
- 디자인 감사를 “눈으로 대충 봄”으로 대체 금지.
|
||
|
||
### 1.3 예외
|
||
|
||
다음은 테스트 선행이 어려울 수 있다. 그래도 문서화가 필요하다.
|
||
|
||
| 예외 | 허용 조건 | 대체 증거 |
|
||
|---|---|---|
|
||
| 문서만 수정 | 코드 동작이 변하지 않음 | 링크/목차/SSOT 일관성 검사 또는 변경 요약 |
|
||
| 설치 스크립트/작업 스케줄러 | 실제 Windows 권한이 필요 | dry-run/PowerShell parser/ASCII/BOM 검사 + 수동 프로브 로그 |
|
||
| 실제 공공 사이트 접근 | 사용자 승인 필요 | fixture/mock 서버 E2E + 수동 실행 체크리스트 |
|
||
| 순수 스타일 문구 | 자동화 어려움 | 디자인 RED 체크리스트와 스크린샷/수기 판정 기록 |
|
||
|
||
예외를 남길 때는 “왜 자동화 못 했는가 / 어떤 수동 증거로 대체했는가 / 나중에 자동화할 조건”을 적는다.
|
||
|
||
---
|
||
|
||
## 2. RED 계층 구조
|
||
|
||
### R0 — 계약/부팅 RED
|
||
|
||
목표: 프로젝트가 import/CLI/패키지 수준에서 깨지지 않음을 보장한다.
|
||
|
||
필수 검사:
|
||
|
||
```powershell
|
||
.\.venv\Scripts\python.exe -m compileall -q src tests
|
||
.\.venv\Scripts\python.exe - <<'PY'
|
||
import importlib, pathlib
|
||
for p in pathlib.Path('src/dmf_crawler').rglob('*.py'):
|
||
if p.name == '__init__.py':
|
||
continue
|
||
importlib.import_module('.'.join(p.with_suffix('').relative_to('src').parts))
|
||
PY
|
||
.\.venv\Scripts\python.exe -m dmf_crawler --help
|
||
.\.venv\Scripts\python.exe -m dmf_crawler doctor --json
|
||
```
|
||
|
||
RED 예시:
|
||
|
||
- `cli.py` 가 없으면 `python -m dmf_crawler --help` 실패.
|
||
- `storage/repo.py` 가 없으면 `pipeline.run_once()` 런타임 실패.
|
||
- `.ps1` 에 BOM 이 없으면 PowerShell 5.1 한글 깨짐 위험.
|
||
|
||
### R1 — 도메인 단위 RED
|
||
|
||
대상:
|
||
|
||
- `normalize.py`
|
||
- `diff.py`
|
||
- `integrity.py`
|
||
- `source_mfds.py` 파서
|
||
- `agy/extract.py` JSON 추출
|
||
|
||
원칙:
|
||
|
||
- 네트워크 없음.
|
||
- DB 없음.
|
||
- clock/random 고정.
|
||
- fixture 로 실패 재현.
|
||
|
||
대표 RED:
|
||
|
||
| 위험 | 테스트 |
|
||
|---|---|
|
||
| 등록번호 파서 회귀 | 표준/신물질/허여서/깨진 입력 10종 |
|
||
| openpyxl 함정 재발 | nedrug xlsx 는 sheet XML 직접 파싱 요구 문서/테스트 |
|
||
| API 오류 봉투 2종 | JSON 정상 봉투 + XML/JSON Gateway 오류 봉투 |
|
||
| 조용한 빈 파일/빈 응답 | 200 OK + 헤더만/0건은 무결성 게이트 차단 |
|
||
| 발급일자 변경 신호 | permit_date 변경 시 CHANGED |
|
||
| 취하 오탐 | totalCount 급감/전건 취하율 임계 초과 시 diff 폐기 |
|
||
|
||
### R2 — 저장소/통합 RED
|
||
|
||
대상:
|
||
|
||
- `storage/db.py`
|
||
- `storage/repo.py`
|
||
- migrations
|
||
- `pipeline.py`
|
||
|
||
필수 RED:
|
||
|
||
- 새 DB 에 migrations 0001~0003 적용.
|
||
- 중복 적용 시 checksum 검증 후 무변화.
|
||
- `start_run` → checkpoint → snapshot → events → report data 조회.
|
||
- 같은 날짜 SUCCESS 중복 방지.
|
||
- 기준선 첫 실행은 이벤트 0건.
|
||
- 스냅샷 저장 전 무결성 실패면 DB 오염 없음.
|
||
|
||
### R3 — 파이프라인 E2E RED
|
||
|
||
목표: 사람이 실제로 쓰는 흐름을 fixture 로 끝까지 검증한다.
|
||
|
||
시나리오:
|
||
|
||
1. **첫 설치/키 없음**
|
||
- `doctor` 가 API 키 없음 WARN 을 낸다. 인증키는 선택 기능이다.
|
||
- `source.mode=auto` 는 API 키가 없으면 AGY headful Chrome CCBAC03 xlsx 수집을 시도한다.
|
||
- `source.mode=api` 에서 키가 없거나 headful 수집이 실패하면 BLOCKED 가 아니라 마지막 성공 자료 PARTIAL 리포트로 폴백한다.
|
||
2. **첫 수집 기준선**
|
||
- fixture API 3건 → DB snapshot 3건.
|
||
- diff 이벤트 0건.
|
||
- 대시보드 배너 “기준선 수립일”.
|
||
3. **둘째 날 변경**
|
||
- 신규 1 / 변경 1 / 취하 1 fixture.
|
||
- events 3건, report changes 3행.
|
||
4. **무결성 차단**
|
||
- 200 OK 이지만 0건.
|
||
- diff/persist 스킵.
|
||
- 마지막 성공 자료로 PARTIAL 리포트.
|
||
5. **리포트 파일 잠김**
|
||
- 대상 xlsx 잠김 또는 `~$` 파일 존재.
|
||
- `_HHMMSS` 폴백 이름 사용.
|
||
- 최신본 갱신 실패는 WARN 으로 기록.
|
||
6. **AI 실패 독립성**
|
||
- agy timeout/schema fail.
|
||
- 리포트는 생성되고 AI 없음 배너만 표시.
|
||
|
||
### R4 — xlsx 디자인 감사 RED
|
||
|
||
DMF Crawler 의 가장 중요한 사용자 화면은 Excel 리포트다. xlsx 는 zip/XML 이므로 stdlib 로 검사한다.
|
||
|
||
필수 감사:
|
||
|
||
| 항목 | RED 조건 |
|
||
|---|---|
|
||
| 파일 구조 | `[Content_Types].xml`, `xl/workbook.xml`, worksheets, styles 존재 |
|
||
| 시트 순서 | 대시보드가 첫 시트, 메타가 마지막, 워치리스트는 조건부 |
|
||
| 시트명 | `00_대시보드` 등 SSOT 명칭과 1:1 |
|
||
| 탭 색 | `report/theme.py` 의 `TAB_COLORS` 반영 |
|
||
| 대시보드 viewport | zoom 90, 행/열 폭 합이 1366×768 무스크롤 목표 초과 금지 |
|
||
| 틀 고정 | 변경분/전체현황/집계 시트에 freeze panes |
|
||
| 자동필터/표 | 데이터 표가 ListObject 또는 autofilter 를 가짐 |
|
||
| 내부 링크 | 대시보드 내비, 변경분→전체현황 링크 존재 |
|
||
| 조건부서식 | 신규/변경/취하/워치/게이트 실패 서식 존재 |
|
||
| 대비 | 팔레트 상태 배경/글자 contrast 최소 AA, 핵심 상태 AAA 목표 |
|
||
| 색 단독 금지 | 신규/변경/취하가 라벨+기호+색으로 표현 |
|
||
| 긴 텍스트 | 한글 긴 성분명/제조소/소재지 fixture 가 열폭 255 같은 폭주를 만들지 않음 |
|
||
| 빈 상태 | 변경 0건, 워치리스트 없음, AI 없음이 깨진 표/빈 차트로 보이지 않음 |
|
||
| 출처 | 식약처/공공데이터포털 출처 문구가 메타/푸터에 존재 |
|
||
|
||
### R5 — GUI 디자인·UX 감사 RED
|
||
|
||
대상: `tkinter` 온보딩/복구 GUI.
|
||
|
||
자동화 전략:
|
||
|
||
- 실제 창을 띄우되 가능하면 withdraw/offscreen 으로 둔다.
|
||
- 위젯 트리(`winfo_children`)를 검사한다.
|
||
- `Entry` 에 실제 텍스트를 넣고 버튼 command 를 호출한다.
|
||
- 텍스트 길이를 늘려 레이아웃 clipping 을 검사한다.
|
||
- geometry propagation 이후 `winfo_reqwidth/height` 와 screen/컨테이너 크기를 비교한다.
|
||
|
||
필수 감사 항목:
|
||
|
||
| 범주 | 실패 조건 |
|
||
|---|---|
|
||
| 끔찍한 중앙 정렬 | 폼 라벨/입력/버튼이 의미 없이 전체 중앙에 뭉쳐 스캔 불가 |
|
||
| 시각적 치우침 | 주요 column/버튼 그룹의 x/y 정렬선이 크게 어긋남 |
|
||
| 폰트 | 본문 10pt 미만, 대비 낮은 muted text, 제목/본문 hierarchy 없음 |
|
||
| overflow | 긴 한글/영문/API 키/경로가 컨테이너 밖으로 나가거나 잘림 |
|
||
| input label | 모든 입력에 visible label 또는 설명 텍스트 없음 |
|
||
| input padding | 입력 내부 텍스트와 경계/버튼 간격이 너무 좁음 |
|
||
| 실제 입력 | API 키/웹훅/워치리스트 텍스트를 넣어도 깨지지 않음 |
|
||
| 버튼 클릭 | [키 입력], [다시 검사], [지금 실행], [로그 열기] command 가 연결됨 |
|
||
| 복합 시나리오 | 키 없음→입력→검증 실패→오류 표시→재입력 흐름이 끊기지 않음 |
|
||
| 아이콘/텍스트 | 아이콘만 있는 버튼에 텍스트/툴팁 없음, vertical align 어긋남 |
|
||
| focus | Tab 순서가 논리적이고 기본 포커스가 위험 버튼에 가지 않음 |
|
||
| 모달 | 닫기/나중에/복구 행동이 명확하고 ESC/창닫기 처리됨 |
|
||
| 자연스러운 한국어 안내 | 온보딩 상단 안내가 `무엇:/왜:/어떻게:/다음:` 같은 AI식 라벨을 노출하지 않고, 현재 막힌 항목과 누를 행동을 1~3개의 자연스러운 문장으로 설명 |
|
||
|
||
### R6 — 브라우저 수집 E2E RED
|
||
|
||
브라우저 수집은 수집용 AGY가 visible/headful Chrome 을 조작하는 경로다. 요약용 AGY와 혼동하지 않는다.
|
||
|
||
- [ ] 전용 Chrome 프로필 Preferences 에 다운로드 경로가 고정된다.
|
||
- [ ] CDP 포트 소유권 sentinel 을 확인하지 못하면 중단한다.
|
||
- [x] `.tmp`/`.crdownload` 가 사라진 뒤 최종 xlsx 만 집는다. (`test_headful_browser_collect_rejects_incomplete_downloads`)
|
||
- [x] 다운로드 파일이 최소 크기/zip 구조/행 수 임계 검증을 통과한다. (`test_headful_browser_collect_validates_download_and_returns_raw_records`)
|
||
- [x] CCBAC03 웹 xlsx 헤더 alias(`신청인`, `제조국가`, `최초등록일자`, `최종변경일자`)를 RawRecord 표준 필드로 매핑한다. (`test_headful_browser_accepts_public_ccbac03_xlsx_headers`)
|
||
- [x] 로그인 상태가 아니면 “세션 만료”로 감지하고 비밀번호를 agy prompt 로 보내지 않는다. (`test_headful_browser_prompt_contract_forbids_headless_http_and_secrets`)
|
||
- [x] `mcp`/`execute_url` permission auto-deny 를 빈 JSON 오류로 뭉개지 않고 원인별로 보고한다. (`test_headful_browser_collect_reports_mcp_permission_denial_from_stderr`, `test_headful_browser_collect_reports_execute_url_permission_denial_from_stderr`)
|
||
- [x] AGY 권한은 `mcp(chrome-devtools/*)`, `execute_url(nedrug.mfds.go.kr)`만 좁게 추가한다. `mcp(*)`, `execute_url(*)`, `--dangerously-skip-permissions` 금지. (`test_headful_mcp_allow_rule_is_scoped_and_does_not_use_dangerous_skip`)
|
||
- [x] 프롬프트는 ambiguous 버튼 클릭 대신 visible Chrome 에서 `/pbp/CCBAC03/getExcel` 을 열고 wrong export 를 guard 한다. (`test_headful_browser_prompt_blocks_wrong_review_result_export`)
|
||
- [x] `source.mode=auto` + API 키 없음은 AGY headful browser 로 라우팅한다. (`test_source_auto_without_api_key_routes_to_headful_browser`)
|
||
- [x] `source.mode=browser` 는 API 키가 있어도 AGY headful browser 를 강제한다. (`test_source_browser_mode_routes_to_headful_even_when_api_key_exists`)
|
||
- [x] 실제 nedrug 접근은 기본 테스트가 아니라 사용 승인 수동 smoke 로 분리한다. 2026-09-03 smoke `run_20260903_130332`: fetch/normalize/persist/report SUCCESS, 9,816건.
|
||
|
||
### R7 — 에이전트 지침/정책 RED
|
||
|
||
`AGENTS.md`, `CLAUDE.md`, 이 문서가 서로 어긋나면 agent 가 나쁜 습관으로 돌아간다.
|
||
|
||
필수 검사 후보:
|
||
|
||
- `AGENTS.md` 가 이 문서를 링크한다.
|
||
- “No code without RED” 규칙이 존재한다.
|
||
- “테스트 약화 금지”가 존재한다.
|
||
- “디자인 감사 RED” 체크리스트가 존재한다.
|
||
- “실패를 숨기지 말 것”이 존재한다.
|
||
- `CLAUDE.md` 는 중복 SSOT 가 아니라 `AGENTS.md`/이 문서 포인터다.
|
||
|
||
---
|
||
|
||
## 3. RED 작성 품질 기준
|
||
|
||
새 RED 는 아래 8문항을 통과해야 한다.
|
||
|
||
1. 어떤 사용자/운영 위험을 막는가?
|
||
2. 어느 요구사항/설계 문서를 근거로 하는가?
|
||
3. 실패했을 때 메시지가 원인을 좁혀 주는가?
|
||
4. 현재 코드에서 실제로 실패하는가?
|
||
5. 실패 이유가 기대한 이유인가?
|
||
6. network/clock/random/shared DB 에 의존하지 않는가?
|
||
7. 같은 위험을 이미 더 강한 테스트가 덮고 있지 않은가?
|
||
8. Green 후에도 리팩터링을 방해하지 않는 행동 중심 테스트인가?
|
||
|
||
통과하지 못하면 RED 가 아니라 메모다.
|
||
|
||
---
|
||
|
||
## 4. RED 통폐합·삭제 기준
|
||
|
||
TDD 는 계속 RED 를 늘리는 행위가 아니다. 테스트 스위트도 제품이다.
|
||
|
||
### 4.1 통합해야 하는 경우
|
||
|
||
- 같은 fixture 로 같은 실패를 여러 테스트가 반복한다.
|
||
- 단위 테스트와 E2E 가 같은 단순 분기만 검사한다.
|
||
- 실패하면 원인이 항상 같은 내부 구현 세부다.
|
||
|
||
처리:
|
||
|
||
- 가장 사용자 의미가 강한 테스트 하나를 남긴다.
|
||
- 나머지는 helper/fixture 로 합친다.
|
||
- 커밋/작업 로그에 “어떤 위험이 어디로 이동했는지” 기록한다.
|
||
|
||
### 4.2 삭제해야 하는 경우
|
||
|
||
- 구현 세부를 강제해 좋은 리팩터링을 막는다.
|
||
- flaky 해서 신뢰를 깎는다.
|
||
- 요구사항이 사라졌다.
|
||
- 더 강한 상위 테스트가 같은 결함을 잡는다.
|
||
|
||
삭제 금지:
|
||
|
||
- 단지 Green 을 만들기 어렵다는 이유.
|
||
- 실행 시간이 길다는 이유만으로 삭제. 먼저 계층 이동/fixture 축소/impact run 을 시도한다.
|
||
|
||
### 4.3 완화해야 하는 경우
|
||
|
||
디자인 임계값(예: 폭/대비/간격)은 완화 가능하지만, 다음이 있어야 한다.
|
||
|
||
- 실패 스크린샷 또는 xlsx XML 증거.
|
||
- 사용자 유즈케이스에서 문제가 되지 않는 이유.
|
||
- 완화 후에도 잡히는 결함 목록.
|
||
|
||
---
|
||
|
||
## 5. 작업 절차 — 에이전트 필수 프로토콜
|
||
|
||
### 5.1 시작 전
|
||
|
||
1. `docs/HANDOFF.md` 를 읽는다.
|
||
2. 이 문서와 관련 설계 문서를 읽는다.
|
||
3. 변경할 파일 목록을 정한다.
|
||
4. 영향 테스트 목록을 쓴다.
|
||
5. 아직 테스트가 없으면 먼저 RED 를 작성한다.
|
||
|
||
### 5.2 구현 중
|
||
|
||
1. RED 를 실행해 실패 로그를 확인한다.
|
||
2. 최소 구현으로 Green 을 만든다.
|
||
3. 관련 테스트를 다시 실행한다.
|
||
4. Green 상태에서만 리팩터링한다.
|
||
5. 전체 smoke 를 돌린다.
|
||
|
||
### 5.3 보고
|
||
|
||
보고에는 최소 다음을 포함한다.
|
||
|
||
- 추가/수정한 RED.
|
||
- RED 실패가 기대한 이유였는지.
|
||
- Green 을 위해 바꾼 파일.
|
||
- 실행한 명령과 결과.
|
||
- 남은 실패/미검증 항목.
|
||
- 디자인 감사 결과(해당 시).
|
||
|
||
---
|
||
|
||
## 6. 영향 테스트 지도 v1
|
||
|
||
| 변경 파일 | 먼저 돌릴 테스트 | 그 다음 |
|
||
|---|---|---|
|
||
| `models.py` | 전체 import, dataclass contract tests | 전체 pytest |
|
||
| `normalize.py` | `tests/test_normalize.py` | diff/integrity/report data |
|
||
| `diff.py` | diff unit tests | pipeline scenario |
|
||
| `integrity.py` | integrity gate tests | pipeline stale fallback |
|
||
| `source_mfds.py` | API fixture parser tests | fetch E2E mock |
|
||
| `storage/db.py` | migration tests | repo/pipeline/report data |
|
||
| `storage/repo.py` | repo roundtrip tests | pipeline/report-only |
|
||
| `pipeline.py` | pipeline fixture E2E | alerts/watchdog/report |
|
||
| `agy/*` | polluted JSON/schema/budget tests | pipeline AI failure independence |
|
||
| `report/data.py` | SQL fixture report data tests | xlsx design audit |
|
||
| `report/*sheets*` | xlsx XML/visual audit tests | report-only smoke |
|
||
| `gui/*` | tkinter structure/input/button tests | onboard smoke |
|
||
| `notify/*`, `alerts.py` | template 4요소/DB state tests | notify-pump once |
|
||
| `scripts/*.ps1` | BOM/parser tests | 수동 Windows registration probe |
|
||
| `AGENTS.md`, `CLAUDE.md` | agent policy contract tests | docs link check |
|
||
|
||
---
|
||
|
||
## 7. 현재 프로젝트에 즉시 필요한 RED backlog
|
||
|
||
이전 구현 워크플로우가 중간에 끊겨 있으므로, 아래 RED 부터 만든다.
|
||
|
||
### 7.1 R0 계약 RED
|
||
|
||
- [x] `test_all_modules_import` — 현재 이름: `test_all_expected_runtime_entry_modules_import` (`tests/test_project_contracts.py`)
|
||
- [x] `test_cli_help_exits_zero` (`tests/test_project_contracts.py`)
|
||
- [x] `test_doctor_json_never_crashes_without_key` (`tests/test_project_contracts.py`)
|
||
- [x] `test_powershell_scripts_have_bom` — 현재 이름: `test_powershell_scripts_have_utf8_bom` (`tests/test_project_contracts.py`)
|
||
- [x] `test_cmd_files_are_ascii_only` (`tests/test_project_contracts.py`)
|
||
|
||
### 7.2 R2 저장소 RED
|
||
|
||
- [x] `test_migrations_apply_to_empty_db` — 현재 이름: `test_migrations_apply_to_empty_db_and_are_checksum_idempotent` (`tests/test_storage_repo.py`)
|
||
- [x] `test_repo_baseline_roundtrip` — 현재 이름: `test_repo_baseline_roundtrip_creates_snapshot_without_events` (`tests/test_storage_repo.py`)
|
||
- [x] `test_repo_changed_withdrawn_events_roundtrip` — 현재 이름: `test_repo_changed_new_withdrawn_events_roundtrip` (`tests/test_storage_repo.py`)
|
||
- [x] `test_same_day_success_is_idempotent` — 현재 이름: `test_same_day_success_is_enforced_by_database_guard` (`tests/test_storage_repo.py`)
|
||
|
||
### 7.3 R3 파이프라인 RED
|
||
|
||
- [x] `test_run_without_service_key_uses_existing_baseline_instead_of_blocking`
|
||
- [ ] `test_first_success_run_creates_baseline_report`
|
||
- [ ] `test_empty_success_body_blocks_diff_and_preserves_previous_snapshot`
|
||
- [ ] `test_agy_failure_does_not_block_report`
|
||
|
||
### 7.4 R4 xlsx 디자인 RED
|
||
|
||
- [x] `test_report_sheet_order_and_names` — `tests/test_report_e2e_design.py` 의 seeded DB → 실제 xlsx XML 감사가 검사한다.
|
||
- [ ] `test_dashboard_has_no_scroll_viewport_budget`
|
||
- [x] `test_report_has_freeze_panes_autofilter_internal_links` — `tests/test_report_e2e_design.py`
|
||
- [x] `test_report_status_styles_are_not_color_only` — `tests/test_report_e2e_design.py` 의 상태 라벨/기호/조건부서식 감사가 검사한다.
|
||
- [ ] `test_report_palette_contrast_ratios`
|
||
- [x] `test_long_korean_values_do_not_create_extreme_column_widths` — `tests/test_report_e2e_design.py`
|
||
|
||
### 7.5 R5 GUI 디자인 RED
|
||
|
||
- [ ] `test_onboard_all_inputs_have_visible_labels`
|
||
- [ ] `test_onboard_can_type_api_key_and_trigger_save_action`
|
||
- [ ] `test_recover_message_explains_problem_and_action_in_natural_korean`
|
||
- [ ] `test_main_actions_have_specific_button_labels`
|
||
- [ ] `test_long_korean_error_text_does_not_exceed_window_budget`
|
||
- [ ] `test_tab_order_reaches_primary_actions_before_secondary_actions`
|
||
- [x] `test_onboarding_footer_buttons_render_visible_text_after_refresh` — 사용자 스크린샷 `C:\Users\encep\AppData\Local\Temp\pi-clipboard-5df73a57-a813-41be-b025-819e48bd73c2.png` 회귀. 하단 버튼이 빈 버튼처럼 보이면 실패해야 한다. (`tests/test_ux_regressions.py`)
|
||
- [x] `test_onboarding_footer_buttons_keep_text_when_required_items_exist` — 필수/권장 조치가 있는 상태에서도 footer 버튼 텍스트가 짜부라지거나 사라지면 실패해야 한다. (`tests/test_ux_regressions.py`)
|
||
- [x] `test_onboarding_row_action_buttons_are_not_clipped_inside_scroll_view` — 행별 액션 버튼이 스크롤 영역/창 하단에 잘리면 실패해야 한다. (`tests/test_ux_regressions.py`)
|
||
- [x] `test_onboarding_new_grouped_layout_keeps_primary_actions_visible` — 새 그룹 레이아웃에서 주요 버튼이 아예 안 보이면 실패해야 한다. (`tests/test_ux_regressions.py`)
|
||
- [x] `test_scroll_frame_mousewheel_scrolls_when_pointer_is_over_content` — scroll canvas 안의 실제 텍스트/카드 위에서 휠을 굴려도 스크롤되어야 한다. (`tests/test_ux_regressions.py`)
|
||
- [x] `test_onboarding_status_panel_names_blockers_instead_of_generic_yellow_info_box` — 상단 안내문은 `무엇:/왜:/어떻게:/다음:` 같은 AI식 라벨이 아니라 자연스러운 한국어 문장이어야 한다. (`tests/test_ux_regressions.py`)
|
||
- [x] `test_agy_google_login_is_optional_when_ai_disabled_for_api_mode` — 공식 API만 쓰고 AI 요약이 꺼져 있으면 AGY/Google 로그인을 요구하지 않는다. (`tests/test_ux_regressions.py`)
|
||
- [x] `test_agy_is_prompted_for_headful_collection_when_auto_has_no_api_key` — auto+API 키 없음이면 AI 요약이 꺼져 있어도 최신 수집용 headful AGY 준비를 안내한다. (`tests/test_ux_regressions.py`)
|
||
- [x] `test_agy_is_prompted_for_forced_browser_mode_even_with_api_key` — browser 모드는 API 키가 있어도 수집용 headful AGY 준비를 안내한다. (`tests/test_ux_regressions.py`)
|
||
|
||
### 7.6 R6 브라우저 수집 RED
|
||
|
||
- [x] `test_headful_browser_prompt_contract_forbids_headless_http_and_secrets`
|
||
- [x] `test_headful_browser_collect_validates_download_and_returns_raw_records`
|
||
- [x] `test_headful_browser_collect_rejects_incomplete_downloads`
|
||
- [x] `test_headful_browser_collect_reports_mcp_permission_denial_from_stderr`
|
||
- [x] `test_headful_browser_collect_reports_execute_url_permission_denial_from_stderr`
|
||
- [x] `test_headful_mcp_allow_rule_is_scoped_and_does_not_use_dangerous_skip`
|
||
- [x] `test_headful_browser_prompt_blocks_wrong_review_result_export`
|
||
- [x] `test_headful_browser_accepts_public_ccbac03_xlsx_headers`
|
||
- [x] `test_source_auto_without_api_key_routes_to_headful_browser`
|
||
- [x] `test_source_browser_mode_routes_to_headful_even_when_api_key_exists`
|
||
- [ ] 전용 Chrome profile Preferences / CDP 포트 sentinel / 스케줄러 headful smoke RED
|
||
|
||
---
|
||
|
||
## 8. 이 문서와 다른 문서의 관계
|
||
|
||
| 문서 | 관계 |
|
||
|---|---|
|
||
| `docs/00-REQUIREMENTS.md` | 사용자 요구 SSOT. 이 문서는 테스트 운영 방법 SSOT. |
|
||
| `docs/design/01-architecture.md` | 아키텍처 SSOT. 이 문서는 검증 게이트를 추가한다. |
|
||
| `docs/design/03-xlsx-report-spec.md` | xlsx 디자인 명세 SSOT. R4 RED 는 이 문서를 실행 가능하게 만든다. |
|
||
| `docs/design/04-onboarding-wizard.md` | GUI 명세 SSOT. R5 RED 는 이 문서를 실행 가능하게 만든다. |
|
||
| `docs/research/11-tdd-red-and-design-audit-theory.md` | 이론/근거 아카이브. |
|
||
| `AGENTS.md` | AI agent 실무 지침. 이 문서를 압축해 적용한다. |
|
||
| `CLAUDE.md` | Claude Code 진입 포인터. 중복 정본이 아니다. |
|
||
|
||
---
|
||
|
||
## 9. 미해결 항목
|
||
|
||
- [x] `tests/test_project_contracts.py` 를 만들어 R0 계약 RED 를 실제 코드화한다.
|
||
- [x] xlsx XML 감사 RED 를 실제 코드화한다. 현재 파일: `tests/test_report_e2e_design.py`.
|
||
- [x] tkinter 구조/입력/버튼 감사 RED 를 실제 코드화한다. 현재 파일: `tests/test_gui_design_contracts.py`, `tests/test_ux_regressions.py`.
|
||
- [x] 브라우저 수집 경로 확정 후 R6 RED 를 코드화한다. 현재 파일: `tests/test_agy_headful_collection.py`.
|
||
- [ ] 영향 테스트 지도를 자동 생성/검증할지 결정한다(TDAD 방식의 단순 텍스트 맵부터 시작).
|