P21 오류 사건과 영향 원본 행 구분 실습
모든 입력은 합성 자료입니다. Python 3.12 표준 라이브러리만 사용합니다.
검증 환경은 logs/runtime.json을 확인하세요. Windows/macOS 앱 실행은 미검증입니다.

압축을 푼 폴더에서:
python3 summarize.py fixtures/population.csv fixtures/errors.csv report-normal.json
기대 종료코드 1: 보고서는 완성되었고 오류가 보고된 원본 행이 있습니다.
source_rows=3, error_events=3, affected_rows=2, rows_without_reported_error=1.
report-normal.json은 새 파일명이어야 하며 같은 이름 재실행은 종료코드 2로 거부합니다.

python3 summarize.py fixtures/multifile_population.csv fixtures/multifile_errors.csv report-multi.json
a.csv/R1과 b.csv/R1은 다른 원본 행입니다. 오류3, 영향2, 분모3.
python3 summarize.py fixtures/population.csv fixtures/no_errors.csv report-no-errors.json
종료0이어도 전체 규칙 검사를 통과했다는 뜻이 아닙니다. coverage=NOT_PROVEN_BY_ERROR_LIST.

duplicate_errors.csv / unknown_errors.csv: 종료2, 새 보고서 없음.
python3 test_summary.py : 12개 단위 검산.
logs/cli_actual.json : 실제 9개 CLI 실행 기록, logs/unittest.txt : 단위 결과.
expected/normal_counts.json : 손으로 정한 정상 요약 정답.

source_file은 파일을 열 경로가 아닌 원본 데이터 묶음의 식별 문자열입니다.
같은 파일명이 다른 폴더/기간에 반복되면 먼저 식별자를 고유하게 정하세요.
규칙 ID도 동일 이름이 동일 의미여야 합니다. 같은 행/규칙의 반복 오류는 자동 합치지 않고 거부합니다.
빈칸/앞뒤 공백의 ID와 규칙은 거부합니다. 대소문자/유니코드 표기는 자동 수정하지 않습니다.
CSV 한 파일 1MB/10,000레코드 수용 한도는 메모리 보장 장치가 아닙니다.
입력은 읽기만 합니다. 기존 출력은 덮어쓰지 않습니다.
쓰기 도중 저장 오류가 나면 일부 새 JSON이 남을 수 있으므로 종료2 결과를 사용하지 마세요.
파일 시스템 전체 트랜잭션이나 동시 입력 변경 감지 기능은 없습니다.

python3 test_cli.py : 추가 CLI 반례를 새 임시 폴더에서 재실행합니다. 제공 로그·기대값·원본은 덮어쓰지 않습니다.
