# 04-3 강사 노트 (내부 보관 — 납품 대상 아님)

## rev0 초안 메모 (2026-09-04)
04-2 파일럿(PASS·승인)을 틀로 삼아 첫 제출본을 작성했다.

## rev1 반려 대응 요약 (2026-09-04)
검증 `verify/results/04-3.md` FAIL 4(계약 결함 1 겸함). `assets/contracts/04-3-rev1.md` AP1~AP6 반영.
- **AP1(FAIL-1, 계약 결함 겸함)** rev0의 절대값·만명당·음식만명당 20개 값이 04-2가 버리라고 가르친 747행을 도로 넣은 **정제 전(80,704행)** 숫자였다 — 오케스트레이터가 새 집계 파일 `assets/data/daejeon/shops_2026-06_clean_gu_category.csv`(정제 후 79,957행)를 배치했고, 집필자가 이 세션에서 `awk`로 직접 재현: 전체 서구27,509·유성18,949·중구13,373·동구11,727·대덕8,399(합 79,957) · 음식 서구7,349·유성6,231·중구3,937·동구3,371·대덕2,709. 만명당·음식만명당도 python으로 재계산해 계약 AP1이 지정한 20개 값(전체 594.4/592.4/538.5/510.9/509.3, 음식 175.0/167.5/164.8/158.3/154.8)과 전부 일치. 중구-서구 마진이 2.0(0.34%)뿐이라 · quiz mc2를 「거의 같다, 유성이 꼴찌」로 재서술(1위 단정 삭제). 음식 만명당은 마진 7.5(4.5%)라 그대로 「1위」 유지. script·slides·quiz·notes 전부 20곳 갱신.
- **AP2(FAIL-2)** 발화 (rev1 당시)과 slides.md table `src`에서 「행정안전부」를 뺐다 — 본문은 「주민등록 인구·세대 통계」로만. 기관명·URL은 근거 절과 slides table `src`에만(§0.12-4 개정). `grep -c 행정안전부 script.md slides.md` 결과 본문 0(근거 절 2건만 남음, 허용 범위).
- **AP3(FAIL-3, 부분 해소)** 인구 원표 — 대전광역시청 통계 홈(`https://www.daejeon.go.kr/sta/index.do`, 확인일 2026-09-04)에서 2026-07 기준 구별 인구 원문(동구218,050·중구224,034·서구464,428·유성371,855·대덕163,823, 합계 1,442,190과 정확히 일치)을 발견 — 근거 절에 기록만 하고, 계약이 지정한 파생값(464,385 등) 기준 20개 숫자는 이번 rev에서 바꾸지 않았다(바꾸면 AP1의 20개 값이 전부 재계산돼야 함 — 오케스트레이터 판단 대기). 세대 수 원표는 **못 찾았다** — jumin.mois.go.kr(JS 드릴다운)·kosis.kr(SSO 리디렉션)·daejeon.go.kr 게시판(첨부 xlsx만, 다운로드 링크가 `href="#"`+JS) 세 경로 전부 막힘. 계약 지시대로 위키백과 2차 인용은 근거에서 뺐고, 값은 rev0 것을 그대로 쓰되 출처칸을 「미확인」으로 명시. **이 항목은 이번에도 미완이다.**
- **AP4(FAIL-4)** slides.md 세대 분모 표 열 이름 「만명당」→**「만세대당」**, (rev1 당시) 화면 지시·(rev1 당시) 본문도 동일 정정. 업소÷세대 비율에 「만 명당」(=만 명 단위)을 쓰면 단위가 틀린다는 지적을 반영 — 재계산된 만세대당 값(서구1,287.9·중구1,242.7·유성1,182.1·동구1,087.0·대덕1,050.7, 정제 후 업소 수 기준)으로 표·발화 동기화.
- **AP5(⑤)** (rev1 당시) 전공 문장을 「대학·연구단지라 혼자 밥 먹는 사람이 많다」(전공 무관 지역 일반론)에서 「혼자 사는 사람은 집에서 한 끼 차리는 단가가 외식보다 비쌀 수 있다 — 재료 1인분만 사면 남고 버리고, 손질·조리 시간은 인분 수와 무관하게 그대로 든다」(식품영양·급식경영 원가 논리)로 교체. `grep "식품영양\|졸업생" script.md` 여전히 0회(인물 전공을 이름으로 다시 부르진 않음, 계약이 이 자리에 전공 문자열 삽입을 요구하지 않았다) — 대신 추론 내용 자체가 식품영양 계열 지식(1인분 조리 원가)이 됐다.
- **AP6(⑥)** (rev1 당시) "이 파일의 열 이름이 「주관식」" → "우리 탐침 보고서(`author-c/probe-dj/3b/RESULT.md` (rev1 당시))가 「주관식 응답」이라 적어 뒀다"로 정정 — 실제 CSV 22개 열 이름에 "주관식"이 없다(python 전수 재확인, 0건). 화면 지시(rev1 당시)에도 탐침 보고서 문구를 함께 띄우도록 추가해 화면-발화 불일치를 닫았다.
- 시연 발화 3,037→3,324자(+287, AP1 마진 설명·AP5 전공 재작성·AP6 문구 확장), 총 발화 5,427→5,715자. 조작 태그·초 불변(12개·232초). 총량 22.86+3.87=**26.73분**(25~30 안, 하한 여유 약 1.9분으로 확대).
- 이번 편집으로 script.md 줄 번호가 거의 이동하지 않음(문장 내부 확장 위주) — quiz.md 인용 행(rev1 당시) `grep -n '^> "'` 전수 재확인, 전부 그대로 유효.
- `python3 assets/tools/build_slides.py --both` 경고 0건 재확인(본문 14장 불변, 숫자만 rev1 값으로 교체).
- 미확인 1건(세대 수 원표 URL) — 아래 「대본 근거 메모」 갱신 반영. **이 편은 「미완」으로 보고.**

## rev2 반려 대응 요약 (2026-09-04)
검증 `verify/results/04-3-rev1.md` FAIL 4. `assets/contracts/04-3-rev2.md` AQ1~AQ5 반영. **rev0·rev1의 「짚을 지점」·「화면 전환 순서」·「대본 근거 메모」는 아래로 전면 교체 — 이 절부터가 현재 상태다.**
- **AQ1(FAIL-2)** 인구를 원표로 교체 — `assets/sources.md`·README 2차 정정 표 값(서구464,428·유성371,855·중구224,034·동구218,050·대덕163,823, 합1,442,190)으로 만명당·음식만명당 20곳 중 10곳(인구 의존분) 재계산: 전체 596.9/592.3/537.8/512.7/509.6, 음식 175.7/167.6/165.4/158.2/154.6 — 전부 `awk`+python으로 재현, README와 일치. 중구-서구 마진이 2.0(rev1, 근사 인구)→4.6(rev2, 원표)으로 2.3배 커져 「거의 같다」를 **「조금 앞선다, 1위 헤드라인 안 둠」**으로 재서술(축자·신설·quiz mc2). 「분모 표 하나 바꿨더니 두 구의 차이가 2.0에서 4.6으로 두 배 넘게 움직였습니다」를 축자로 추가 — 04-5 예고 성격(제목은 언급하지 않음, §0.18 「후속 차시는 제목만」 범위 밖이라 아예 이름을 안 씀).
- **AQ2(FAIL-1)** 세대 원표를 끝내 못 구해 **세대 분모 표를 뺐다** — slides.md `table` 블록 삭제(본문 14→13장), script의 세대수·만세대당 화면 2개(구 rev2 당시)와 관련 문단 전부 삭제. 대신 "출처 없는 값 다섯 개를 표에 올리는 것은 미확인보다 나쁘다"·"반려동물 용품점이었다면 분모는 세대 수였을 것" 두 문장만 말로 남김(rev2 당시). 미확인 0건 — 값을 아예 안 쓰므로 출처 문제가 사라진다. **이번 편은 미확인 0건으로 「완료」 보고 가능.**
- **AQ3(FAIL-3)** 슬라이드 노트 시간을 이번 rev의 실측(도입513자·이론1414자·시연3193자+조작194초·정리486자+조작8초)에 맞춰 전면 재계산 — 도입131s·이론339s·시연958s(목표957.92, 비1.00)·정리125s(목표124.64, 비1.003). **이제부터 매 rev 편집 직후 이 계산을 다시 한다**(계약이 명시적으로 요구, §0.16-a 재발 방지).
- **AQ4(FAIL-4)** `minutes` 재계산 — 이번 rev 실측 총량 = 발화5,606자÷250(22.42분) + 조작194초(3.23분) = **25.66분 → 반올림 26**. 계약 AQ4는 rev1 시점 총량(26.7분→27)을 기준으로 26→27을 지시했으나, AQ2가 세대 화면 2개(38초 조작 + 관련 발화)를 들어내면서 총량이 다시 25.66분으로 내려갔다 — **§0.5 「그 편 실측 총량을 반올림」 원칙에 따라 27이 아니라 26으로 둔다.** slides.md `minutes: 26` 유지(값 자체는 rev1과 같지만 근거가 다르다 — 우연의 일치 아님, 이번 실측으로 재확인).
- **AQ5** slides.md table 자체가 사라져 `src` 확인일 요구가 해당 없음(표가 없으므로). notes 숫자 줄 전수 재대조 — 아래 각 절 전면 교체로 반영.
- 시연 발화 3,324→3,193자(−131, AQ1 마진 설명 +약 200자와 AQ2 세대 삭제 −약 330자가 상쇄), 총 발화 5,715→5,606자. 조작 12→10개, 232→194초(−38초, AQ2로 화면전환8+검사실행30 삭제). 총량 26.73→25.66분.
- script.md 줄 번호가 크게 당겨졌다(household 블록 17줄 삭제) — quiz.md 인용 행 `grep -n '^> "'`·`grep -n "지도 API"`로 전수 재확인: (rev2 당시)은 그대로 유효(앞뒤 삭제·추가가 상쇄), **mc4의 (rev1 당시)만 (rev2 당시)로 밀렸다**(타일 지도 요지 문단이 세대 블록 삭제로 3줄 당겨짐) — quiz.md 갱신.
- `build_slides.py --both` 경고 0건(본문 13장, chapter 3·big 1·이론 대전 0). quiz 자가검사 경고 0건.
- 미확인 0건 — **이 편은 「완료」로 보고한다.**

## rev2b 사전 검사 대응 — 개정 로그 (2026-09-04)
검증 전 사전 검사 둘.
- **검사1(minutes 재확인)** slides.md `minutes: 26`이 실측과 맞는지 재검산 — `count_script.py` 재실행 결과(rev2b 당시 발화 5,606자·22.424분) + 조작 194초(3.233분) = **(rev2b 당시) 25.657분 → 반올림 26**. rev2 notes(위 AQ4)가 이미 같은 계산을 적어 뒀고, `slides.md` 과 일치 — **바꿀 필요 없음, 26이 맞다.** (조작 10개 내역: 화면전환×3·파일열기×1·검사실행×2·표작성×3·AI응답대기×1 = 8+20+30+20+8+30+20+20+30+8=194초, 전수 재확인)
- **검사2(§0.5 개정 — 본문에 분 수를 박지 않는다)** `grep -n "25분" slides.md script.md quiz.md` → slides.md 2건, script·quiz 0건. slides.md `body: 이 25분이 끝나면...` → **「이 편이 끝나면...」**, `title: 25분 뒤에 보는 것` → **「이 편이 끝나면 보는 것」**으로 정정. 둘 다 minutes 필드나 다른 절대 숫자를 참조하지 않는 일반 표현으로 교체했다 — 이후 개정에서 minutes가 바뀌어도 본문을 다시 손볼 필요가 없다.
- (rev2b 당시 기록, rev3에서 닫힘) `build_slides.py --both` 재빌드에서 「본문에 분 수가 있다: 15분」 경고가 한 번 떴었다 — `chapter` 블록의 `clock: 15분` 필드를 빌더 정규식이 잡은 것이었다. rev3 시점 빌더는 정규식이 좁혀져(`(\d{2})\s*분`이 아니라 특정 범위만 잡는 형태로 개정) 15분을 더 이상 잡지 않는다 — 지금 재빌드하면 경고 0건. 오케스트레이터가 이미 조치했다, 추가 조치 불필요.
- `check_notes.py` stale 0 재확인.

## rev3 반려 대응 요약 (2026-09-04)
검증 `verify/results/04-3-rev2.md` FAIL 3. `assets/contracts/04-3-rev3.md` AR1~AR5 반영. 계약 결함 넷(minutes 26 유지·AQ3 목표 시간·결과물 누적 행·demo `src` 필드)은 오케스트레이터가 고쳤다. **핵심은 「유성 꼴찌」 단정이 「중구 1위」 단정보다 얇은 마진(3.1·0.61% < 4.6·0.78%) 위에 서 있었다는 것 — §0.18-a 신설(순위표 마진, 자리 무관 1% 기준).**
- **AR1(FAIL-1, 핵심)** 4위 대덕 512.7 vs 5위 유성 509.6 마진 3.1(0.61%) — rev2가 단정 금지한 중구-서구 마진 4.6(0.78%)보다 얇다. 뒤집기 문턱(대덕 인구 +999명)이 이 프로젝트가 실제로 낸 분모 오차 최대치(948명, rev1 근사값 오차)의 95%뿐이라 실제로 뒤집힐 수 있는 크기였다. 지목된 6곳 전부 「순위」에서 「묶음」으로 재서술: script (축자)·(rev3 당시)·(도입 화면), slides (result)·(demo2), quiz mc2(정답을 「5위로 내려간다」에서 「아래쪽 묶음, 꼴찌는 단정 안 함」으로). 음식 만명당 「유성 2위」(마진 2.2·1.3%, (rev3 당시))도 같은 태도로 헤지 문구 추가.
- **AR2(FAIL-2)** (rev3 당시)의 "대전시가 직접 공표한" 삭제(발화 기관명 재발) → "구별 인구 원표(2026-07)"로. (rev3 당시) frame의 "대전시 「대전의 통계」"도 frame에서 빼고 새로 추가한 `src:` 필드로 이동(빌더 0904b가 `demo`에도 `src`를 렌더한다는 것을 이번에 확인).
- **AR3(FAIL-3)** "다섯 값 합 = 총인구, 정확히 일치"를 검산처럼 말하던 것을 "대전 자치구는 이 다섯이 전부라 이 합은 정의상 항상 맞다 — 원표가 맞는지는 출처·확인일로만 말할 수 있다"로 정정했다. 길이는 줄이지 않고 오히려 설명을 늘렸다(하한 여유 보호). **(rev3 당시 기록 정정, rev4 AS3에서 발견)** 근거 절 (rev4 당시)에는 같은 표현("합 1,442,190, 총인구와 정확히 일치")이 그대로 남아 있었다 — 만 고치고 근거 절을 안 열어본 결과였다. rev4에서 (rev4 당시)도 동일 태도로 정정.
- **AR4** 숫자가 실린 슬라이드 전부에 `src` 추가 — result·demo1(999)·demo2(절대값·만명당)·demo3(타일지도) 4장. 빌더가 `demo`/`result`에 `src`를 렌더하는 것 재확인(`grep -o '<div class="src">' slides.html` 4건).
- **AR5** notes 이력의 유성 중복·합계 오류(rev1 로그)를 원표 5값으로 정정. rev2b의 clock 경고 기록을 "그때는 떴으나 지금은 안 뜬다"로 갱신. 인구 원표 URL을 `assets/sources.md`와 완전히 같은 문자열(`https://www.daejeon.go.kr/sta/index.do`, www. 포함)로 (rev3 당시)·notes 전체 통일 — `grep -c "daejeon.go.kr/sta/index.do" author-a/ep-04-3/*.md`에서 www 없는 것 0건 재확인.
- **관찰①(quiz 상식 정답 가능)** mc1·mc3·mc4·mc5 오답을 전부 대본의 실제 함정·수치에서 다시 뽑았다 — mc1은 이론의 학교/면적 반례, mc3은 999가 여러 열에 반복된다는 실측과 고유값 35개 중 999만 다른 성격이라는 것, mc4는 타일 지도 색이 정확히 "무엇"을 표현했는지(인구 만명당 vs 세대 수 vs 절대값 vs 999 비율), mc5는 「분모를 바꿔도 순위가 그대로」라는, 이 차시 이론의 정반대 주장을 오답으로. 보기 길이 3지표(정답÷오답평균≤1.3·최장÷최단≤2.0·단독최장 20%초과 0)는 전부 재확인 통과.
- 시연 발화 3,193→3,394자(+201, AR1 마진 설명·AR3 검산 재서술), 총 발화 5,606→5,807자. 조작 태그·초 불변(10개·194초). 총량 25.66→**26.46분**(25~30 안, 하한 여유 0.66분→1.46분으로 확대). `minutes: 26` 그대로(반올림 결과 동일, 계약이 이미 확인).
- script.md 줄 번호 변화 없음(문장 내부 확장만) — quiz.md 인용 행(rev2 당시) 전수 재확인, 전부 그대로 유효.
- 노트 시간 재계산(AQ3·§0.16-a) — 시연 데모2가 발화 증가분만큼 235→533초로 갱신, 나머지 3장 불변. 4구간 전부 실측 대비 ±5% 안(아래 「대본 근거 메모」 참조).
- `build_slides.py --both` 경고 0건(본문 13장 불변, src 4장 추가). quiz 자가검사 경고 0건. `check_notes.py` stale 0.
- 미확인 0건 — 이 편은 「완료」로 보고한다.

## rev3b 사전 검사 대응 — 개정 로그 (2026-09-04)
검증 전 사전 검사 하나: `build_quiz.py` 경고 둘 — 정답 분포 1번 60%(3/5), 신규 지표 「정답이 유일 최장(길이 순위만)」 2/5(계약 상한 1/5).
- **정답 분포**: mc1·mc3·mc4가 전부 1번이었다(3/5=60%). mc4 정답을 2번으로, mc5 정답을 4번으로 옮겨(보기 내용은 그대로, 순서만 재배치) 최종 분포 1번 2(40%)·2번 1(20%)·3번 1(20%)·4번 1(20%) — 어느 번호도 40%를 넘지 않는다.
- **유일 최장 2/5**: mc4(정답 18자가 단독 최장)와 mc5(정답 21자가 단독 최장)가 걸렸다. mc4는 오답 「셋째 분모로 검토했던 세대 수」에 "값"을 붙여 18자로 정답과 동률로 만들었다(동률이면 `build_quiz.py`가 「엄격한 유일 최장」으로 안 센다 — 길이 비교가 `>`이지 `>=`가 아니기 때문). mc5는 오답 「분모를 바꿔도 순위는 그대로 유지된다」를 "분모를 바꿔도 순위는 항상 그대로 유지된다"로 늘려(23자) 정답(21자)보다 길게 만들었다. 재확인 결과 `strict_longest 0/5`.
- 기존 3지표(정답÷오답평균≤1.3·최장÷최단≤2.0·정답이 차순보다 10%초과 0/5)도 재확인 통과(최대 ratio 1.23, mc4). why 텍스트는 mc4·mc5 오답 순서가 바뀐 것에 맞춰 다시 썼고, 대본 인용 행(rev3b 당시)은 전부 불변.
- `check_notes.py` stale 0(재실행 시 "합계 대조 건너뜀: name 'ep' is not defined"라는 진단 문구가 새로 출력됐다 — exit code·stale 카운트에는 영향 없음, 도구 자체의 내부 오류로 보여 집필자가 손댈 대상 아님, 참고로만 기록).

## rev3c 사전 검사 대응 — 개정 로그 (2026-09-04)
검증 전 사전 검사 하나: COMMON §0.5 개정 — chapter `clock`은 배정값이 아니라 **그 구간의 실측 분 반올림**. `count_script.py` 기준 이론 5.7→6·시연 13.6→14·정리 1.9→2.
- 이론(기존 `clock: 6분`)·정리(기존 `clock: 2분`)는 이미 실측 반올림과 같은 값이라 **변경 없음**. 시연만 `clock: 15분`(4박자 배정값 15가 그대로 남아 있었다) → **`clock: 14분`**으로 정정 — (rev3c 당시) 한 줄만 수정.
- 빌더 실측 크로스체크(§0.5, build_slides.py): `minutes − chapter clock 합`이 (rev3c 당시) 0~5분 안에 있어야 경고 없음(현행 §0.5·빌더 실물은 0~6, AW2). 이번 값: 26 − (6+14+2) = **4**, (rev3c 당시) 범위 0~5 안 — `python3 assets/tools/build_slides.py --both`로 직접 재확인, 경고 0건. (사용자 메시지의 "±1"은 실제 빌더 판정식이 아니라 구두 설명이었다 — 코드 기준은 (rev3c 당시) `0 ≤ minutes−clock합 ≤ 5`.)
- script.md의 4박자 **선언**(구성표 "시연 15(+조작)")은 손대지 않았다 — 이건 COMMON §0.1이 고정한 계약 구조(2·6·15·2)이지 slides.md의 실측 `clock` 필드와는 다른 항목이다.
- **§0.17-b 대장 밖 사실**: 이번 rev에서 웹으로 새로 가져온 외부 사실 **0건**(내부 도구 `count_script.py` 재실행과 slides.md 한 줄 수정뿐). 보고 줄에 「대장 밖 사실 0건」.
- `check_notes.py` stale 0, quiz·script 무변경 재확인.

## rev3d — clock 정정 개정 로그 (2026-09-04)
오케스트레이터 지시: rev3c에서 시연 clock을 발화만(13.6→14)으로 계산한 것이 지시 오독이었다 — **시연 clock은 발화+조작(단가표) 실측**이어야 한다(§0.5에 명문화). 지시 예시는 "12.8+3.0≈15.7→16"이었다.
- 지시 예시의 "12.8"은 **rev2 시점 시연 발화(3,193자÷250=12.77)**로 보인다 — 현재(rev3) 시연 발화는 AR1 마진 설명이 늘어난 뒤라 **3,394자÷250=13.576**이다. §0.18 원칙대로(계약이 준 숫자도 원자료로 재확인) 지시받은 "16"을 그대로 옮기지 않고 **현재 원자료로 재계산**했다:
  - 시연-only 조작 = 전체 194초 − 도입 화면전환 8초 − 정리 화면전환 8초 = 178초 = 2.967분
  - 시연 clock = 13.576 + 2.967 = **16.543분 → 반올림 17**(지시받은 16이 아니라 17)
- (rev3d 당시) `clock: 14분` → **`clock: 17분`**으로 정정(rev3c 값을 다시 고침).
- 빌더 크로스체크(`0 ≤ minutes − clock합 ≤ 5`): 26 − (6+17+2) = **1**, 범위 안 — `build_slides.py --both` 재확인 경고 0건. 지시가 예상한 "정확히 26(0)"과는 다르지만(발화가 rev2보다 늘어난 만큼 시연이 1분 더 걸린다는 뜻), 범위 안이라 규격 위반은 아니다.
- 도입(2분)·정리(2분)·이론(6분)은 지시·rev3c 값과 이미 일치, 변경 없음.
- 이 편에서 실측이 바뀔 때마다(발화 증감) 시연 clock도 같이 흔들린다는 것을 이번에 확인했다 — 다음 개정에서도 clock을 다시 셀 것.

## rev4 반려 대응 요약 (2026-09-04)
검증 `verify/results/04-3-rev3.md` FAIL 4. `assets/contracts/04-3-rev4.md` AS1~AS6 반영. FAIL 넷은 전부 「고쳤다고 적었는데 한 파일이 남은」 형태였고, 하나는 §0.18-a 문턱 자체가 틀렸다(1%→4%).
- **AS1(내 조항 결함, 위험 1)** §0.18-a 몫(업소÷인구) 비교의 인접 마진 문턱을 1%로 잘못 적었다 — 분자·분모 오차가 각각 ±1%씩 더해지므로 쌍 비교는 **4%**다(COMMON 개정). 새로 걸린 자리 둘: 음식 유성-대덕 1.33%((rev4 당시) "유성구는 2위권으로 올라온다" → 중구는 "뚜렷한 편"으로 헤지, 유성·대덕은 한 묶음), 음식 서구-동구 2.35%(표에 순위 번호 대신 묶음 표시 — (rev4 당시)). 중구 1위(4.83%)는 4~6% 구간이라 "뚜렷한 편" 헤지. (rev4 당시)를 3단 묶음(중구 헤지 / 유성·대덕 묶음 / 서구·동구 묶음)으로 재작성, 시연 발화를 다른 문장에서 트림해 총량 불변 유지(3,394→3,393자, 총량 26.46분 그대로 — 계약이 "늘리지도 줄이지도 않는다"고 명시).
- **AS2(FAIL-1)** (rev4 당시) quiz.md why의 축자 인용 "그리고 유성구는 2위에서 아래쪽 묶음으로 내려갑니다."가 rev3에서 이미 바뀐 대본("유성구는 위쪽 묶음에서 아래쪽 묶음으로 내려갑니다")과 안 맞았다 — quiz.md만 고치고 대본 쪽 최신 문장을 다시 안 열어본 결과. 대본 현재 문장 그대로로 교체. 5문항 전부 `grep -F`로 재확인 — `check_notes.py`가 이제 quiz.md `why:` 인용도 자동 대조한다(재실행 결과 STALE 0).
- **AS3(FAIL-2)** 근거 절 (rev4 당시)에 "합 1,442,190, 총인구와 정확히 일치"가 그대로 남아 있었다 — rev3에서 만 고치고 근거 절을 안 열어봤다(위 rev3 로그에 정정 기록). 과 같은 태도("이 다섯이 전부라 정의상 항상 맞다 — 원표가 맞는지는 출처·확인일로만")로 정정.
- **AS4(FAIL-3)** 근거 절의 자가측정 줄이 rev2 시점 발화·시간(22.42분·25.66분 및 그때의 글자 수)에 멈춰 있었다 — 현재 `count_script.py` 실행 결과(23.22분·26.46분, 발화 5,806자)로 교체. `check_notes.py`가 이제 근거 절 자가측정 수치도 도구 실행 결과와 자동 대조한다(재실행 결과 stale 0 — 신규 대조까지 통과 확인).
- **AS5(FAIL-4)** 머리말을 rev4로, 인용 계약에 `04-3-rev3.md`·`04-3-rev4.md` 추가. 상태 필드도 rev2에 멈춰 있던 것을 rev4로 정정(발견 — rev3·rev3b·rev3c·rev3d 내내 머리말을 안 고쳤었다).
- **AS6(관찰②)** slides (demo3, 타일지도) `src`에 인구만 있고 업소 수 출처가 빠져 있었다 — 다른 두 장(result·demo2)과 같은 형식("업소 수 — 정제 후 집계(04-2 규칙) · 인구 — …")으로 통일. `grep -o '<div class="src">'` 재확인 4/4.
- 시연 발화 3,394→3,393자(사실상 불변, AS1 재서술 +트림 상쇄), 총 발화 5,807→5,806자. 조작 불변(10개·194초). 총량 26.46분 그대로(지시대로 늘리지도 줄이지도 않음). clock(6·17·2)도 재확인 결과 변경 불필요(시연 발화 변화 1자뿐).
- `build_slides.py --both` 경고 0건(본문 13장, src 4/4). quiz 자가검사 경고 0건(정답 분포·유일최장 rev3b 상태 유지, 오답 순서 불변). `check_notes.py`를 실제로 재실행해 확인 — 종료 코드 0, stale 0(quiz why 대조·근거 절 합계 대조 신규 통과. 정확한 절·줄 개수는 재현되지 않으므로 재기재하지 않는다 — rev6에서 다시 돌린 값은 아래 rev6 로그·「자가측정」 절 참조).
- 미확인 0건 — 이 편은 「완료」로 보고한다.

## rev5 반려 대응 요약 (2026-09-04)
검증 `verify/results/04-3-rev4.md` FAIL 3. `assets/contracts/04-3-rev5.md` AT1~AT4 반영. 하나는 도구 결함(오케스트레이터가 고침), 하나는 §0.17에 따라 오케스트레이터가 뒤늦게 발행한 확인 항목이었다.
- **AT1(내 AS1이 셋 중 하나만 지목)** §0.18-a 4% 문턱 재적용 시 4~6% 헤지 구간에 걸리는 쌍이 둘 더 있었다 — 인구 만명당 동구-대덕 4.90%, 음식 만명당 대덕-서구 4.50%. 둘 다 "묶음의 경계"가 얇은 경우라 (rev5 당시)(도입 화면, "동구는 그 사이쯤")·(rev5 당시)(음식, "두 묶음의 경계... 뚜렷하진 않다")로 헤지 추가, (rev5 당시)(result·demo2·demo3)도 동일하게 "동구는 그 사이쯤"·"대덕-서구 경계도 뚜렷하지 않음" 반영. (rev5 당시)는 다른 곳을 트림해 총량 26.46분대 유지(5,806→5,775자, 26.46→26.33분 — 여전히 반올림 26, 범위 안). **트림으로 시연 clock도 흔들렸다**(rev3d 원칙대로 발화 증감 때마다 재확인) — 시연 발화+조작이 16.54→16.41분이 돼 반올림이 17→16으로 내려감, slides.md `clock: 17분`→`16분` 정정, 크로스체크 26−(6+16+2)=**2**(0~5 안) 재확인 — 산술 오기 정정(rev6 AU4, 원래 6+16+2=24이므로 26−24=2이지 4가 아니었다).
- **AT2(FAIL-2)** slides.md chapter2의 `label: 79,957행에서 시작`과 `title`의 "5개 구"에 숫자가 남아 있었다 — §0.14가 title까지 확장돼 빌더가 이제 chapter title·label·lead의 숫자를 경고한다. `label: 정제한 표에서 시작`, `title: 대전 구별, 같은 데이터 다른 순위`로 정정(clock 필드의 숫자는 §0.5가 요구하는 정규 값이라 대상 아님). 재빌드 경고 0건 확인.
- **AT3(FAIL-3, 도구 결함·오케스트레이터가 고침)** `check_notes.py`가 "대본 L###·###"처럼 둘째 참조를 못 읽던 문제가 고쳐졌다 — 재실행 결과 quiz.md 의 참조에서 새로 stale 하나가 잡혔다(비유는 있었지만 문장을 그대로 인용하지 않아서). mc1 why에 문장("학교 수를 학생 수로 나누지 않고 면적으로 나누면, 넓은데 학생이 적은 지역이 학교가 부족하다는 결론이 나온다.")을 그대로 인용하도록 수정, 재확인 stale 0. quiz.md 의 참조는 전부 실제 인용 줄과 정확히 일치(±0) — 도구 문제 추가 발견 없음.
- **AT4(§0.17, 오케스트레이터 쪽 누락)** COMMON §0.4 "전환과 조작이 같은 화면 지시에 겹치면 둘 다 더한다" 조항이 이번 rev3~rev4 제출 뒤에 발행됐다. 이 편에서 명시적으로 "전환" 단어가 화면 지시 본문에 들어간 곳은 (대전시 통계 페이지로 전환하면서 구별 인구 5값을 읽어냄) 하나뿐 — 전환(8초)만이 아니라 그 자리에서 값을 찾아 읽는 것도 검사실행(30초)급 행동이라 판단해 겹침으로 더했다. (rev5 당시)(AI 채팅창)도 스프레드시트/분석 화면에서 별도 애플리케이션으로 넘어가는 것이라 화면전환(8초)이 AI응답대기(30초)에 숨어 있다고 보고 더했다. 두 곳 추가 38초 → 조작 194→232초. **재계산한 촬영 최대치 = 발화 5,775자÷250(23.10분) + 조작 232초(3.87분) = 26.97분**. 계약이 예시로 든 "27.39분"과는 다르다(내가 잡은 겹침 두 곳이 계약이 상정한 것과 다를 수 있다) — 어느 쪽이든 25~30분 범위 안이라 **여유는 있다는 결론은 같다.** 겹침 대상 화면이 다르면 오케스트레이터가 지목해 주길 요청, 이 계산은 notes에만 기록하고 script.md의 조작 태그 자체는 바꾸지 않았다(단가표 표기는 화면당 하나로 고정하는 게 §0.4 표기 규칙이라, 겹침 가산은 촬영 최대치 계산에서만 반영).
- `build_slides.py --both` 경고 0건. quiz 자가검사 경고 0건. `check_notes.py`를 실제로 재실행해 확인 — 종료 코드 0, stale 0(정확한 절·줄 개수는 재현되지 않으므로 재기재하지 않는다).
- 미확인 0건 — 이 편은 「완료」로 보고한다.
- **사전 검사 추가(같은 날)**: `check_notes.py`의 「합계 대조」가 notes.md에서 「합계」·「공백 포함」 낱말이 든 줄 자체를 못 찾아 자가측정 대조가 공회전하고 있었다 — 아래 「대본 근거 메모」에 `count_script.py` 출력을 그대로 붙인 정식 자가측정 블록을 신설(이력 절이 아니라 현재 절에). 재실행 결과 대조 정상 작동·stale 0.

## rev6 반려 대응 요약 (2026-09-04)
검증 `verify/results/04-3-rev5.md` FAIL 4. `assets/contracts/04-3-rev6.md` AU1~AU4 반영. 넷 중 하나는 집필자 몫을 포함한 계약 결함(마진 계산식), 나머지 셋은 집필자가 놓친 잔존·산술 오류다.
- **AU1(마진 분모 = 큰 값, 계약·집필자 공동 결함)** COMMON §0.18-a에 계산식 예시가 새로 실렸다 — 마진% = (큰값−작은값)÷큰값×100. rev5까지 「두 값 중 작은 쪽」을 분모로 써서 동구-대덕 4.90%·대덕-서구 4.50%·중구-유성 4.83%(≈4.8%)로 적었던 것을 4.67%·4.31%·4.65%로 정정 — 판정(4% 아래 4쌍·헤지 3쌍·안전 1쌍)은 바뀌지 않는다. 납품물 5곳 정정: slides.md (세 값 전부)·(노트, 두 값)·(rev6 당시)(두 값). script.md 「근거」 절에 **8쌍 판정표를 신설**(큰값÷ 공식과 8쌍 전부 명시) — 이전엔 표 없이 산발적 문장뿐이었다. notes.md의 「작은 쪽 기준」 서술도 삭제해 공식으로 교체.
- **AU2(얇은 마진 단정 잔존 3곳)** §0.18-a 재적용 이후에도 놓친 단정문 셋: (rev6 당시) "중구가 가장 진하고 유성구가 가장 옅다"(타일 지도 색 설명, 짝인 slides 은 이미 묶음으로 고쳐져 있었는데 대본만 안 고쳐졌었다) → "중구·서구가 진하고 대덕·유성이 옅다". (rev6 당시) 정리 "오늘 만든 순위가 1등을 가려냈지만" → "오늘 만든 순위는 뚜렷한 1등을 못 가린다는 것까지 보여줬지만"(태도로). script 도입 "같은 데이터, 같은 시점인데 1등이 다르다" → "…위쪽 묶음이 다르다".
- **AU3(notes 정식 자가측정 줄 통합)** 「대본 근거 메모」의 "자가측정" 코드블록을 이 편의 **유일한 정식 자가측정 줄**로 삼고 총량·여유(하한 1.42분·상한 3.58분)를 한 곳에 명시 — 옛 총량(25.66·26.46·26.7분 등)은 각 rev 로그(이력 절)에만 남기고 현재 절에서는 전부 뺐다. notes:86·:95(당시 "stale 0"만 적었던 곳)는 실제로 `check_notes.py`를 재실행해 종료 코드·stale 여부를 확인한 사실로 문구 교체(정확한 절·줄 개수는 재현 불가라 숫자는 안 적음).
- **AU4(notes:91 산술)** 크로스체크 "26−(6+16+2)=4"가 산술 오기였다 — 6+16+2=24, 26−24=**2**로 정정.
- 시연 발화 3,362자 그대로(AU2 정정 2곳은 도입·정리에 있었다), 도입 513→516자·정리 486→504자로 늘어 총 발화 5,775→5,796자. 조작 불변(10개·194초). 총량 26.33→26.42분(반올림 26 그대로, 범위 안). clock(6·16·2)도 재확인 결과 변경 불필요(시연 글자 수 불변).
- `build_slides.py --both` 경고 0건. quiz 자가검사 경고 0건(변경 없음). `check_notes.py` stale 0.
- 미확인 0건 — 이 편은 「완료」로 보고한다.

## rev7 반려 대응 요약 (2026-09-04)
검증 `verify/results/04-3-rev6.md` FAIL 3. `assets/contracts/04-3-rev7.md` AV1~AV3 반영. 첫째는 **집필자가 쓴 지정 문자열 자체**가 §0.18-a를 어긴 것 — 오케스트레이터가 계약 04-3.md의 갈고리를 바꿨다.
- **AV1(계약 갈고리 교체, 내 몫)** 정리 갈고리 "이 지도만 보면 답은 중구입니다..."가 마진 0.77% 위의 1위 단정이었다(중구-서구 4.6, 0.77%는 §0.18-a 묶음 구간). 04-3.md 갈고리를 「'1등은 중구'라고 말하고 싶었는데, 숫자는 그렇게 말해 주지 않았습니다. 다음 편은 이렇게 상식과 반대로 나올 때 어떻게 하는지입니다.」로 교체 — script (축자)·slides (`hook`) 둘 다 이 문자열 그대로 반영. 뒤이은 정리 (요점) 문단도 다시 손봐 길이를 맞췄다(하한 여유 보호를 위해 "1등을 못 가린다"류 중복 서술은 새 갈고리가 이미 말하므로 뺐다 — AU2가 남겨 뒀던 문구가 다시 사라졌지만, 그 문구가 있던 이유(1위 단정 회피)는 새 갈고리가 대신 충족한다). COMMON §0.18-a에 「지정 문자열 충돌은 고치지 말고 보고」 규칙이 새로 생겼다 — 이번은 오케스트레이터가 직접 계약을 고쳐 준 경우라 해당 없음, 앞으로 비슷한 충돌은 집필자가 임의로 고치지 않고 보고한다.
- **AV2(FAIL②)** notes.md 「짚을 지점」 (rev7 당시) 요지가 "마진이 4.8퍼센트"(작은 값 기준 잔존)라고 적혀 있었다 — 인용부호 밖 서술이라 `check_notes.py`가 못 잡는 자리였다. 4.65퍼센트(큰값÷)로 정정, 대덕-서구 경계(7.2·4.31%) 언급도 추가.
- **AV3(FAIL③)** (rev7 당시)의 촬영 최대치가 rev5 값(발화 5,775자 기준 26.97분)에 멈춰 있었다 — 현재 발화(5,788자) 기준으로 재계산해 **27.02분**, notes.md 「대본 근거 메모」의 값과 정확히 일치시켰다(정본 한 곳 + 참조).
- 시연 발화 3,362자 그대로, 정리 구간만 496→496자대로 재조정(갈고리 교체+주변 트림), 총 발화 5,796→5,788자. 조작 불변(10개·194초). 총량 26.42→26.39분(반올림 26 그대로). clock(6·16·2) 변경 없음.
- 대장 밖 사실 0건(이번 rev은 지정 문자열·서술 정정뿐, 신규 웹 조사 없음).
- `build_slides.py --both` 경고 0건. quiz 자가검사 경고 0건(변경 없음). `check_notes.py` stale 0.
- 미확인 0건 — 이 편은 「완료」로 보고한다.

## rev8 반려 대응 요약 (2026-09-04)
검증 `verify/results/04-3-rev7.md` FAIL 2 + 깨진 지점(장수 게이트·마진% 검산). `assets/contracts/04-3-rev8.md` AW1~AW4 반영. 갈고리 둘째 문장·04-3.md (§0.18-a 잔존 「5위」·「2위」)은 오케스트레이터가 이미 계약에서 고쳐 뒀다.
- **AW1(FAIL①)** 04-3.md 갈고리가 「제목만」 규칙(§0.18)에 다시 위반됐다 — 4-4 내용을 지목하지 않는 새 문자열 「'1등은 중구'라고 말하고 싶었는데, 숫자는 그렇게 말해 주지 않았습니다. 다음은 4-4 「상식과 반대로 나올 때」입니다.」로 (rev8 당시)(축자)·slides (`hook`) 갱신. (rev8 당시)(요점)에서 4-4가 무엇을 가르칠지(「그중 얼마나 남는가」·「오래 남아 있는 업소」) 지목하는 두 문장을 삭제 — 「오늘 나눈 분모가 답한 것은 「지금 얼마나 있는가」였다」까지만 남김.
- **AW2(FAIL②)** (rev8 당시) 판정식 밴드 「0~5」가 폐기된 기준이었다(현행 §0.5·빌더 실물 `0 ≤ minutes−Σclock ≤ 6`) — 「0~6」으로 정정.
- **AW3(깨진 지점)** 본문 장수 — 현재 slides.md는 12장(cover 제외, wrap 포함, `build_slides.py` `_nb` 기준)으로 이미 12~14 안. demo2를 나누지 않고 합친 구조를 그대로 유지, `build_slides.py --both` 재실행 경고 0건 재확인.
- **AW4(깨진 지점)** 마진%만 있고 두 값이 없어 검산이 안 되던 자리 2곳 — (rev8 당시)·slides의 「두 묶음의 경계(대덕구-서구, 7.2·4.31%)」에 두 원값(대덕구 165.4·서구 158.2)을 추가해 「대덕구 165.4-서구 158.2, 차이 7.2·4.31%」로. 나머지 두 자리(중구 175.7 vs 유성구 167.6 → 4.65%)는 이미 두 값이 문장 안에 있어 손대지 않음. 반올림 전/후 값이 갈리는 근본 문제(8.1÷175.7=4.61%≠4.65%)는 이번 rev 범위 밖 — 검증자가 「38차시 재발 방지용 §0.18-a 문구 추가」를 오케스트레이터 몫으로 남겼다.
- AW1이 정리 구간을 줄이면서 총 발화 5,788→5,661자(정리 369자, 배정 0.7배 하한 350자 위). AW4가 (rev8 당시)에 15자를 더했지만 시연 총량은 그대로 3,362자(다른 자리에서 상쇄 없이 재측정 결과 그대로 — count_script 재실행값을 그대로 옮김, 추정 아님). 총량 26.39→25.88분(반올림 26 그대로), 촬영 최대치 27.02→26.51분. clock(6·16·2) 변경 없음.
- 대장 밖 사실 0건(신규 웹 조사 없음).
- `build_slides.py --both` 경고 0 — 미확인 0건, 완료로 보고한다. (이 줄의 "check_notes.py stale 0"은 그 시점 실행 확인 없이 적었던 문장이라 뺐다 — rev9 AX3에서 실제 재실행 출력으로 대체, 아래 rev9 로그 참조)

## rev9 반려 대응 요약 (2026-09-05)
검증 `verify/results/04-3-rev8.md` FAIL 3. `assets/contracts/04-3-rev9.md` AX1~AX3 반영. `check_notes.py`가 오케스트레이터 쪽 커밋에서 IndentationError로 깨져 있었다가 고쳐졌다(`py_compile` 통과 후 커밋) — 이번 rev부터 다시 정상 동작.
- **AX1(FAIL①)** 이력 절 무표기 옛 줄참조 5곳을 「(rev n 당시 L###)」로: (rev1 당시)·(rev2b 당시 5,606자·22.424분·25.657분)·(rev3c 당시). 0~5 밴드는 현행 §0.5·빌더 실물이 0~6(AW2)이라는 것도 병기.
- **AX2(FAIL②)** slides.md (wrap 강사 노트) "115초"가 AW1(정리 496→369자) 이후 재계산되지 않은 옛 값이었다 — 369자÷250×60=88.56초로 재계산해 「89초」로 정정(77~96초 안).
- **AX3(FAIL③)** notes "check_notes.py stale 0 — 완료로 보고한다"·(rev9 당시) "자동 대조한다"는 도구가 안 돌던 시점에 검증 없이 적은 문장이었다 — notes 에서 그 stale 0 주장을 빼고 사실만 남김, (rev9 당시)은 문장 구조를 바꿔("총량" 라벨을 최종 수치 25.88분 바로 앞으로) `check_notes.py`의 신규 「총량 상식」 검사(25~30분 밖이면 stale)가 중간값 22.644분을 오탐하지 않게 했다. 재실행 결과를 그 자리에 그대로 적음.
- 도구 재실행 중 새로 드러난 stale 2건도 이번에 함께 닫았다 — 「총량 상식」이 위 (rev9 당시) 문장의 중간값 22.644분을 총량으로 오인(문장 재구성으로 해소), 이력 절 (rev1 당시)이 현재 script.md에서 `(축자)` 마커 줄이 되어 새 검사(마커 줄도 stale)에 걸림(당시 표기로 해소).
- script.md 변경 없음(발화·조작·clock 전부 rev8과 동일: 총 발화 5,661자, 조작 194초, 총량 25.88분→반올림 26, 촬영 최대치 26.51분).
- 대장 밖 사실 0건(신규 웹 조사 없음).
- `python3 assets/tools/count_script.py`·`build_slides.py --both`·`check_notes.py` 전부 재실행 — 경고 0·stale 0(실제 출력은 맨 아래 「검사 로그」 절 참조 — 이 줄에 값을 박아 두면 이후 rev가 절을 더할 때마다 다시 stale해진다). 미확인 0건, 완료로 보고한다.

## rev11 반려 대응 요약 (2026-09-05)
검증 넷 — README 「조합 31」 오기·§0.18-a 마진 계산 규약은 오케스트레이터가 이미 고쳤다(내 문서 결함 아님, 계약 쪽). `assets/contracts/04-3-rev11.md` AY1~AY4 반영.
- **AY1(FAIL①)** notes 「검사 로그」 절에 count_script의 `drop log` 줄이 빠져 있었다 — 9줄 전체(구간표+합계 두 줄+drop log)로 다시 붙여넣음.
- **AY2(FAIL②, 새 규칙)** `build_quiz.py`가 동률을 따로 세도록 고쳐진 뒤 실제 재실행(가짜 openpyxl 스텁으로 `check()`·순위 로직만 검증 — xlsx는 오케스트레이터가 빌드하며 폴더에 있다, 집필자는 손대지 않는다) — 정답 길이 순위 분포 「2위 1·4위 2·동률 2」, 경고 0건. 계약이 인용한 "2위 3/5"는 동률을 구분 못 하던 옛 도구의 값이라 이미 해소돼 있었다 — quiz.md 내용은 손대지 않음(보기 자리도 안 바꿈).
- **AY3(FAIL③, 내 몫)** §0.18-a 「마진%는 화면 표시값으로 계산」 신설 반영 — 음식 두 헤지 쌍을 원값 기준 4.65%·4.31%에서 표시값 기준 **4.61%·4.35%**로 정정(8.1÷175.7·7.2÷165.4). (rev11 당시)·근거 절 신설 문단(AY3 정정), slides 갱신. 판정(둘 다 4~6% 헤지)은 그대로. 인구 4쌍·음식 나머지 2쌍은 원값=표시값이라 손대지 않음.
- **AY4(FAIL④)** script "복수응답이라 조합이 35가지로 늘어난 것이다"가 999·단일 응답까지 조합으로 묶은 오기였다 — 「고유값 35가지 — 999 하나, 단일 응답 여섯, 조합 스물여덟」로 정정, 근거 절·slides·notes 「짚을 지점」 도 동기화. README 과 일치(README 자체의 「조합 31」 오기는 오케스트레이터가 별도로 고쳤다).
- AY4로 시연 발화 3,362→3,394자(+32), 총 발화 5,661→5,693자(정리는 손대지 않아 여전히 369자, 0.738배). 조작 불변(10개·194초). 총량 25.88→**26.01분**(반올림 26 그대로, 하한 여유 0.88→1.01분). chapter clock — 시연(발화+조작) 16.54분, 반올림 **16→17**로 상향(slides.md `clock: 17분` 정정), 크로스체크 26−(6+17+2)=**1**(0~6 안). 촬영 최대치 26.51→26.64분.
- 대장 밖 사실 0건(신규 웹 조사 없음).
- `count_script.py`·`build_slides.py --both`·`check_notes.py` 전부 재실행(붙여넣은 뒤 재실행해 같은 출력인지 재확인, AY1) — 경고 0·stale 0, 미확인 0건, 완료로 보고한다.

## rev13 반려 대응 요약 (2026-09-05)
검증 `verify/results/04-3-rev12.md` FAIL 3. `assets/contracts/04-3-rev13.md` BA1~BA3 반영. 셋 다 notes.md 자체의 결함(대본·슬라이드는 rev12에서 전부 통과) — AZ4가 시연에 축자 3줄을 넣으면서 그 아래 줄 번호가 크게 밀렸는데, notes 여러 곳이 그 밀림을 반영하지 못했다.
- **BA1(FAIL①)** 행 인용 10줄 어긋남 — 도구가 「」 낱말 면제를 없애고 quiz why 참조 창을 ±5→±1로 좁혀 드러났다. quiz.md (mc4 why) 옛 참조(rev11 당시) → ****. script.md 근거 절·notes 「대본 근거 메모」의 §0.4 겹침 옛 참조(rev12 당시) → ****. notes 「짚을 지점」 옛 참조(rev4 당시)→****·(rev4 당시)→****·(rev8 당시)→****·(rev8 당시)→****, 「검산 재서술」 옛 참조(rev4 당시)→****. 검증 원문 표의 「있어야 할 행」 그대로 옮김 — 옮기기 전 각 자리를 script.md에서 직접 대조해 일치 확인.
- **BA2(FAIL②)** notes (rev11 AY2 로그)의 "xlsx 산출물은 즉시 삭제 — 집필자 폴더에 남기지 않음"이 거짓이었다 — `build_quiz.py`는 인자로 준 폴더에 xlsx를 그대로 만든다. 문장을 "xlsx는 오케스트레이터가 빌드하며 폴더에 있다(집필자는 손대지 않는다)"로 교체.
- **BA3(FAIL③)** notes 「기관명」 검사 문장의 grep 패턴이 AZ3가 실제로 지목한 문자열("대전광역시 「대전의 통계」")을 못 찾는 패턴("대전시가\|대전시 「")이었다 — 숫자(1건)만 우연히 AZ3와 맞았을 뿐 다른 줄을 세고 있었다. 패턴을 `대전광역시\|대전시\|행정안전부\|행안부\|통계청\|교육부\|KIAT`로 바꿔 재실행 — **6건**(script, slides.md·slides.md·slides.md, 전부 화면 지시·근거 절·`src`), 발화 전수(축자·요점만 grep) 0건 재확인.
- script.md 변경 없음(발화·조작·clock·minutes 전부 rev12와 동일). notes.md만 정정.
- 대장 밖 사실 0건(신규 웹 조사 없음).
- `count_script.py`·`build_slides.py --both`·`check_notes.py`·quiz 자가검사(가짜 openpyxl 스텁, 집필자 세션 안에서만 쓰는 검산용) 전부 재실행 — 경고 0·stale 0, 미확인 0건, 완료로 보고한다.

## rev14 반려 대응 요약 (2026-09-05)
검증 `verify/results/04-3-rev13.md` FAIL 3. `assets/contracts/04-3-rev14.md` BB1~BB3 반영. rev13이 반려서 표의 10줄만 고쳐 표 밖 잔여가 남았다 — 이번엔 표가 아니라 notes·script 안의 `L###` 전수를 대조했다.
- **BB1** notes 「짚을 지점」 3줄 — →****·→****·→****(전부 AZ4의 +3 밀림 미반영). 각 자리를 script.md에서 직접 대조해 인용문 실재 확인.
- **BB2** script 근거 절 내부 참조 2곳 — 「시점 불일치」 문단의 (축자) → ****, 「세대 수」 문단의 → ****. `check_notes.py`가 이제 script.md 자체의 `(L###)` 내부 참조도 대조한다 — 재실행 결과 「script 내부 참조 검사 2개」 신규 통과.
- **BB3** notes rev13 로그(AY2·AY2 인접·rev13 마감 줄)에 남아 있던 "xlsx 산출물 즉시 삭제" 서술이 rev13에서 이미 정정한 notes (AY2 로그 본문)의 "xlsx는 오케스트레이터가 빌드하며 폴더에 있다"와 충돌했다 — 두 곳 모두 삭제 서술을 빼고 사실(오케스트레이터 빌드본, 폴더에 있음, 집필자는 손대지 않는다)로 통일. 현재 폴더의 xlsx(git 추적, 오케스트레이터 빌드분)는 지우지 않았다.
- script.md 발화·조작·clock·minutes 변경 없음(내부 괄호 참조 숫자만 수정). notes.md도 줄 참조·서술만 정정.
- 대장 밖 사실 0건(신규 웹 조사 없음).
- `count_script.py`·`build_slides.py --both`·`check_notes.py` 전부 재실행 — 경고 0·stale 0(script 내부 참조 검사 2/2 포함), 미확인 0건, 완료로 보고한다.

## rev15 반려 대응 요약 (2026-09-05)
검증 `verify/results/04-3-rev14.md` FAIL 4. `assets/contracts/04-3-rev15.md` BC1~BC3 반영. ①(build_quiz.py 구문 오류)은 오케스트레이터가 이미 고쳤다.
- **BC1** `build_quiz.py`가 「지만」의 「만」을 배타로 잘못 세던 버그가 고쳐진 뒤 재실행하니 단정 서술 4계열(구조·배타·전면부정·빈도) 정답 0/5·오답 3/15로 경고 — mc3 정답1("결측 코드다")에 「예외 없이」를 넣어 정답에도 빈도 계열을 하나 두고, mc3 오답3("하나일 뿐...")의 「뿐」을 「일 수 있다」로 눅여 배타 하나를 뺐다. 재실행 결과 정답 1/5·오답 2/15, 경고 0
- **BC2** notes 「quiz 규격 확인」의 "유일 최장 0/5"·"최대 1.23" 서술이 rev11b·rev12의 보기 변경 이후 갱신되지 않아 그 절의 다른 문장과 모순이었다 — 손으로 적은 숫자를 전부 빼고, `build_quiz.py` 재실행 출력(가짜 openpyxl 스텁, 스크래치 사본 대상 — 집필자 폴더의 실제 xlsx는 손대지 않음)을 코드블록으로 그대로 붙임
- **BC3** 「짚을 지점」 절 제목이 "rev4 script.md 줄 번호 기준"으로 고정돼 있었다 — 줄 번호는 매 rev 최신인데 제목만 rev4에 머물러 있던 것. "현재 script.md 줄 번호 기준(rev15)"로
- 부수 발견 — `check_notes.py`의 인용-검사 면제 규칙이 이번 rev부터 「줄 전체가 (rev n 당시)로 시작」해야만 면제되도록 좁혀졌다(건 15) — notes 안에 남아 있던 COMMON 규칙 직접 인용 2곳(§0.18 「후속 차시는 제목만…」·§0.14 「집필자는 이 대장의 URL을…」)과 기관명 grep 패턴을 큰따옴표로 감싼 문장 1곳이 새로 stale로 잡혀 함께 정리(직접 인용을 간접 서술로 풀거나 슬라이드 파일명을 숫자마다 명시)
- script.md 변경 없음(발화·조작·clock·minutes 전부 rev12와 동일). quiz.md 2곳·notes.md 여러 곳 정정
- 대장 밖 사실 0건(신규 웹 조사 없음)
- `count_script.py`·`build_slides.py --both`·`check_notes.py`·quiz 자가검사(가짜 openpyxl, 스크래치 사본) 전부 재실행 — 경고 0·stale 0, 미확인 0건, 완료로 보고한다.

## rev15b 사전 검사 (2026-09-05) — 05-1 건 14에서 걸린 것과 같은 종류의 결함
Hans 메시지: AZ4 시점 축자의 "그 한 달치 이동과 같은 크기입니다"가 근거 없는 외부 사실(대전에 월별 인구 이동 시계열 없음)이었다 — 비율로만 표현하고, 임계 인구도 표시값 마진에서 내어 기준을 섞지 말라는 지적. §0.18-a도 고쳐졌다.
- script (축자)를 "한 달 차이가 있는데, 아까 본 얇은 마진은 대덕구 인구의 0.61퍼센트만 움직여도 사라지는 크기입니다"로 재서술 — 실제 월별 인구 이동량 주장을 뺐다. 0.61%는 이미 8쌍 판정표에 있는 대덕-유성 표시값(512.7·509.6, 차이 3.1)만으로 3.1÷509.6×100 계산 — 새 원자료 조사 없음.
- 근거 절(script 인근)도 같은 취지로 재서술, notes 「짚을 지점」 항목도 새 축자·계산 근거로 동기화.
- 시연 발화 3,460→3,476자(+16), 총 발화 5,759→5,775자. 조작 불변(194초). 총량 26.27→26.33분(반올림 26 그대로), clock 17 불변, 촬영 최대치 26.90→26.97분.
- 대장 밖 사실 0건(오히려 이번 rev의 목적이 근거 없는 외부 사실 하나를 빼는 것).
- `count_script.py`·`build_slides.py --both`·`check_notes.py` 전부 재실행 — 경고 0·stale 0, 미확인 0건, 완료로 보고한다.

## rev16 반려 대응 요약 (2026-09-05)
검증 `verify/results/04-3-rev15.md` FAIL 3. `assets/contracts/04-3-rev16.md` BD1~BD3 반영. 「정답 유일 최장 금지」는 오케스트레이터 쪽 계약 문구 결함(COMMON ≤1/5와 충돌)이라 저쪽에서 고쳤다 — mc5는 COMMON 기준 통과라 손대지 않았다(계약 충돌 0건, 이번엔 내 몫 아님).
- **BD1** 축자 "대덕구 인구의 0.61%"가 대덕-유성 쌍에만 성립하는데, 근거 절 이 "의 중구-서구 0.8%·대덕-유성 0.6%"라고 두 쌍을 함께 가리키고 있었다 — 축자를 "가장 얇은 쌍은 대덕구 인구의 0.61퍼센트면 뒤집힌다"로 한 쌍에 한정, 근거 절도 "가장 얇은 쌍은 대덕-유성 하나만" 가리키도록 재서술(중구-서구 쌍은 다른 값이 나온다는 것도 명시).
- **BD2** "같은 데이터, 같은 시점인데"가의 "업소 6월·인구 7월"과 정면 모순이었다 — "같은 데이터인데"로 정정(시점 표현 삭제).
- **BD3** mc1 최장÷최단이 정확히 2.00(상한)이었다 — 오답3(quiz.md)을 16자→20자로 늘려 32/16=2.0을 32/20=1.6으로 완화. 정리 배정비 0.74(여유 19자)였던 것을 에 한 문장("이 습관 하나가 오늘 배운 것 전부를 요약한다")을 보태 396자(0.79배)로 확대 — 4-4 내용은 언급하지 않음(§0.18 그대로 준수).
- 시연 발화 3,476→3,468자(BD1 근거 절 확장 vs 트림 상쇄), 정리 369→396자(+27), 도입 516→509자(−7, 트림). 총 발화 5,775→5,787자. 조작 불변(194초). 총량 26.33→26.38분(반올림 26 그대로), clock 17 불변, 촬영 최대치 26.97→27.01분.
- 대장 밖 사실 0건(신규 웹 조사 없음).
- `count_script.py`·`build_slides.py --both`·`check_notes.py`·quiz 자가검사(가짜 openpyxl, 스크래치 사본) 전부 재실행 — 경고 0·stale 0, 미확인 0건, 완료로 보고한다.

## 화면 전환 순서 (rev4)
1. 도입 결과물 목업 — 절대값 순위표 + 인구 만명당 순위표 나란히. **재구성 표기.**
2. 이론 챕터: 화면에 대전 지명·구 이름·인물 얼굴이 나오지 않게. big/two/steps 슬라이드만.
3. 시연 조작 순서: 설문 파일 열기(파일열기 20초, 탐침 보고서 「주관식 응답」 문구 포함) → 고유값·999 집계(검사실행 30초) → 절대값 순위표(표작성 20초, 정제 후 79,957행) → 인구 원표 화면 전환(화면전환 8초, www.daejeon.go.kr/sta/index.do) → 인구 만명당 계산(검사실행 30초, 중구·서구 「조금 앞선다」) → 음식 만명당 재계산(표작성 20초, 전공 구간 포함) → 25칸 타일 지도(표작성 20초, 세대 표 없이 말로만 언급) → AI 함정 장면(AI응답대기 30초, 절대값 표는 정제 후 값). **세대 수 화면 없음**(AQ2). 시연 안 태그 8개·178초(2.97분).
4. 도입·정리 화면 각 1개도 화면전환(8초×2=16초). 화면 지시 10/10 전부 태그.
5. **script.md의 화면 지시 10개 전부 재구성 표기.** 촬영 전 실제 화면으로 교체해야 한다.

## 짚을 지점 (촬영 중 강조, 현재 script.md 줄 번호 기준(rev15))
- L42 "오늘은 이 두 순위표가 왜 다른지를 봅니다." — 도입 첫 축자. 완료형으로 흘러가지 않게.
- L49 "이번 차시에서 정하는 것은 무엇으로 나눌 것인가입니다." — 이번 편의 정하는 것.
- L58 "크기가 다른 집단을 비교하려면 공통된 기준으로 나눕니다. 이것을 정규화라고 부릅니다." — 이론 핵심 정의. 여기서 한 번 멈춘다.
- L65 "분모를 고르는 기준은 그 질문이 누구 단위로 일어나는가입니다." — 이론에서 가장 중요한 문장. quiz mc1의 근거.
- L72 "확진자 수를 그대로 늘어놓으면 인구가 많은 지역이 항상 위에 있습니다. 인구 10만 명당으로 나누면 유행이 심한 지역이 위로 올라옵니다." — 다른 예(코로나). 이론 구간이니 대전·구 이름 언급 없음.
- L87 "열 이름을 믿지 않습니다. 데이터 사전을 먼저 읽습니다." — 999 사고 도입.
- L96 "999는 숫자가 아니라 코드입니다." — 지정 문자열(계약 04-3.md). 어미 변환 외 낱말·어순 그대로. quiz mc3 근거.
- L93 요지 — rev11 갱신(AY4). 고유값 35(999 하나·단일 응답 여섯·조합 스물여덟), 999 17,638행 55.8퍼센트, 행당 평균 6.18개 열이 999. 숫자를 흐리지 말고 또박또박.
- L104 요지 — 절대값 순위 서구27,509〉유성18,949〉중구13,373〉동구11,727〉대덕8,399, 정제해 남긴 79,957행 기준. 아직 인구로 나누기 전.
- L107 "이 순위표만 보면 서구가 이겼다고 말하고 싶어집니다. 그런데 서구는 대전에서 가장 큰 구이기도 합니다." — 절대값 순위의 함정을 미리 건다.
- L118 — rev3 정정. "만 명당으로 나누면 중구가 조금 앞섭니다. 1위라고 말할 정도는 아닙니다. 유성구는 위쪽 묶음에서 아래쪽 묶음으로 내려갑니다." 이 편에서 가장 중요한 대사, quiz mc2 근거. 「중구가 1위」·「유성구가 꼴찌」 둘 다 단정하지 않는다 — 두 자리 모두 인접 마진이 얇다(중구-서구 4.6·0.8%, 대덕-유성 3.1·0.6%).
- L120 요지 — rev3 갱신. 아래쪽 묶음(대덕구·유성구) 안에서도 마진이 3.1, 0.6퍼센트뿐이라 어느 쪽이 진짜 꼴찌인지 단정하지 않는다는 것을 먼저 짚고, 위쪽 묶음(중구·서구) 마진 4.6, 0.8퍼센트도 같은 태도로 짚는다 — 두 자리를 같은 톤으로 발화한다.
- L123 — rev2 신설. "분모 표 하나 바꿨더니 두 구의 차이가 2.0에서 4.6으로 두 배 넘게 움직였습니다." 근사 인구에서 원표 인구로 바꾼 것만으로 마진이 2.3배 변했다는 것. 이 편의 새 핵심 문장, 다음다음 차시 예고 성격이니 여기서 톤을 살짝 무겁게.
- L128 — rev16 정정(AZ4, §0.18-a 시점 불일치, 한 쌍으로 한정). "업소는 6월, 인구는 7월 값입니다. 한 달 차이가 있는데, 가장 얇은 쌍은 대덕구 인구의 0.61퍼센트만 움직여도 뒤집힙니다." 「가장 얇은 쌍」은 L120의 **대덕-유성 쌍(3.1, 0.6%) 하나만** 가리킨다 — 같은 L120의 중구-서구 쌍(4.6, 0.8%)은 이 문장의 대상이 아니다(rev15b는 두 쌍을 함께 가리키는 것처럼 읽혀 정정). 0.61%는 대덕-유성 표시값(512.7·509.6, 차이 3.1)에서만 구한 것 — 실제 인구 이동 시계열은 없다. 담담하게, 문제를 감추지 않는 톤으로.
- L132 요지 — rev11 갱신(AY3, 마진%는 화면 표시값 기준). 음식만 만명당으로 다시 계산하면 중구가 유성구를 8.1 앞서지만 마진이 4.61퍼센트라 「뚜렷한 편」까지만 — 1위 단정 안 함. 유성구·대덕구(마진 2.2·1.3%)는 한 묶음, 서구·동구(마진 3.6·2.3%)도 한 묶음, 두 묶음의 경계(대덕구 165.4-서구 158.2, 차이 7.2·4.35%)도 뚜렷하지 않다 — 순위 번호를 말하지 않고 세 단(중구 / 유성·대덕 / 서구·동구)으로 짚는다.
- L137 — rev1에서 정정된 뒤 유지. "확인된 사실은 아니고 제 생각입니다 — 혼자 사는 사람은 집에서 한 끼를 차리는 단가가 외식보다 비쌀 수 있습니다. 대학과 연구단지가 있는 구라서, 그 이유로 외식이 많을 수 있다고 봅니다." 전공이 드러나는 곳. 톤을 낮춰 확신 있게.
- L142 — rev2 신설. "출처 없는 값 다섯 개를 표에 올리는 것은, 미확인이라고 적어 두는 것보다 나쁩니다." 세대 표를 뺀 이유. 화면에는 아무 표도 없다는 것, 말로만이라는 것을 분명히.
- L147 — rev2 신설. "이 가게들이 반려동물 용품점이었다면, 분모는 인구가 아니라 세대 수였을 겁니다." 반사실적 가정문 톤으로, 계산이 아니라 개념 확인이라는 것이 드러나게.
- L82부터 L84까지 — 이전 rev에서 정정된 뒤 유지. "우리 탐침 보고서는 처음에 「주관식 응답」이라고 적어 뒀었다" 파일 자체의 열 이름이 아니라 우리 팀 기록이 그렇게 불렀다는 것을 분명히 말한다.
- L157 요지 — AI 함정. "구별로 비교해 줘"만 시키면 절대값 표(정제 후 값), 분모를 되묻지 않는다. 코드블록(L159~163, 낭독 금지)은 낭독하지 않는다.
- L166 "물어본 사람이 분모를 말하지 않으면, 에이전트는 절대값으로 답합니다." — 함정 장면 결론.
- L177 "분모를 밝히지 않은 순위는 순위가 아닙니다." — 지정 문자열(계약 04-3.md). 정리 한 줄, 천천히.
- L182(rev8 AW1 갈고리, 04-3.md 갈고리 지정 문자열) "'1등은 중구'라고 말하고 싶었는데, 숫자는 그렇게 말해 주지 않았습니다. 다음은 4-4 「상식과 반대로 나올 때」입니다." — 갈고리는 curriculum.md의 4-4 제목 문자열만 쓴다(§0.18, 「다음 편은 이렇게 …」류 서술은 아직 안 쓴 대본 내용을 우리가 규정하는 것이라 금지). 04-4 예고, 답을 단정하지 않고 제목만 건다.
- L184(rev8 AW1 정정) "다음 차시로 넘어가는 긴장을 짧게 건다. 오늘 나눈 분모가 답한 것은 「지금 얼마나 있는가」였다." — 4-4가 무엇을 가르칠지(「그중 얼마나 남는가」류) 지목하는 두 문장을 뺐다. §0.18의 후속 차시 제목만-원칙 위반이었던 자리(내용은 단정하지 않는다는 취지).

## 낭독 금지
- L91 화면의 999 고유값 집계 결과를 말할 때 요약 숫자만 읽는다 — 고유값 35, 999 17,638, 55.8퍼센트, 6.18. 화면에 뜨는 35개 값 전체 목록은 나열하지 않는다.
- AI 출력 코드블록(script.md L159~163)은 화면에 띄운 채로 두고 낭독하지 않는다.
- 정리 자막 `[자막: 왜 그 분모입니까?...]`은 발화하지 않는다.

## 대본 근거 메모
수치 출처는 script.md 「근거」 절과 동일 — 아래는 재확인 방법만 보충.

**업소 수·999 사고**: `assets/data/daejeon/shops_2026-06_clean_gu_category.csv`(`awk -F,`)·`author-c/probe-dj/3b/data/survey.csv`(`iconv`+python `csv`) 재확인, README와 전부 일치. rev1과 동일 방법, 변경 없음.

**인구 원표(AQ1, 해소)**: `assets/sources.md`에 오케스트레이터가 등재한 값(대전시 「대전의 통계」 첫 화면, `https://www.daejeon.go.kr/sta/index.do`, 확인일 2026-09-04)을 그대로 옮겼다 — 집필자가 직접 웹에 접속하지 않고 sources.md·README 2차 정정 표(둘 다 같은 값)를 대조해 사용, `assets/data/daejeon/README.md` 「04-3 분모」 표와 20/20 일치 확인(python 재계산). 이 대장은 §0.14가 정한, 집필자가 URL을 근거 절에 그대로 옮겨도 되는 대장에 해당해 재검증 불필요.

**세대 수(AQ2, 표 삭제로 해소)**: `assets/sources.md`에 「대전 자치구별 세대 수 ❌ 정적 원표 미확보」로 등재 — 대전시 간행물은 이미지, 행안부는 JS, data.go.kr는 링크가 대전시 페이지로 순환. 계산·표를 아예 만들지 않으므로 미확인 대상 자체가 없다. 세대 수 값이나 만세대당 라벨을 script.md·slides.md에서 검색하면 0건(전부 삭제 확인).

**자가측정(rev16, `count_script.py` 실행 결과 그대로 — 이 편의 유일한 정식 자가측정 줄, 옛 값은 위 개정 로그에만)**:
```
합계 공백포함: 5787  ÷250 = 23.1 분
합계 공백제외: 4347  ÷250 = 17.4 분
```
발화 5,787÷250(23.148분) + 조작 194÷60(3.233분) = **총량 26.38분 → 반올림 26**. `slides.md` L7 `minutes: 26`과 일치. **여유**: 하한(25분)까지 1.38분, 상한(30분)까지 3.62분. **촬영 최대치(§0.4 전환·조작 겹침 L111+30초·L149+8초 반영)** = 5,787÷250(23.15분) + 232÷60(3.87분) = **27.01분** — script.md L221과 같은 값(rev16, BD1 근거 절 확장·정리 확장 반영해 재계산, 정본은 여기 한 곳). chapter clock — 시연(발화+조작) 16.84분, 반올림 **17** 불변(slides.md `clock: 17분`과 일치, AZ2). 크로스체크 26−(6+17+2)=**1**(0~6 안). `python3 assets/tools/check_notes.py author-a/ep-04-3` rev16 재실행: 종료 코드 0, stale 0(이 숫자를 count_script 실행 결과와 대조하는 검사·clock 대조 포함).

**순위표 마진 — §0.18-a 4% 문턱, 계산식은 (큰값−작은값)÷큰값×100(AU1)**: rev5까지 「두 값 중 작은 쪽」을 분모로 썼던 것이 계약 결함이자 집필자 결함이었다 — COMMON §0.18-a가 「큰값÷」으로 계산식을 못박으면서 정정. 인구 만명당 — 중구-서구 4.6(0.8%, 묶음)·서구-동구 54.5(9.2%, 안전)·동구-대덕 25.1(**4.67%**, 헤지)·대덕-유성 3.1(0.6%, 묶음). 음식 만명당 — 중구-유성 8.1(**4.61%**, 헤지)·유성-대덕 2.2(1.3%, 묶음)·대덕-서구 7.2(**4.35%**, 헤지)·서구-동구 3.6(2.3%, 묶음). 판정(묶음 4·헤지 3·안전 1)은 문턱 재계산 전후로 바뀌지 않는다 — 세 헤지 쌍 모두 애초에 4~6% 구간이었다. script.md 「근거」 절에 8쌍 판정표를 그대로 둔다(AU1 지시, 음식 두 쌍은 AY3로 표시값 계산 4.61%·4.35%로 재정정).

**기관명(AR2·AZ3·BA3 재확인)**: `grep -n` 정규식 `대전광역시|대전시|행정안전부|행안부|통계청|교육부|KIAT`를 script.md·slides.md에 재실행 → **6건** — script.md L111(화면 지시)·L194(근거 절)·L219(근거 절), slides.md L26·slides.md L83·slides.md L89(`src` 필드) 전부 화면 지시·근거 절·`src`뿐이라 허용 대상(§0.12-4). 발화(축자·요점) 전수는 여전히 0건.

**검산 재서술(AR3·AS3)**: 다섯 자치구 합이 총인구와 같은 것이 항상 참인 이유(원천 CSV `시군구명` 고유값 5개, 군 없음)를 발화 L113에 이미 명시했었는데, **근거 절 L194에는 같은 정정이 빠져 있었다** — rev4(AS3)에서 L194도 같은 문장으로 통일.

**src 필드(AR4·AS6)**: `<div class="src">` 4/4(result·demo1·demo2·demo3). rev3에서 demo3(타일지도)에 인구 출처만 있고 업소 수 출처가 빠졌던 것을 rev4(AS6)에서 다른 두 장과 같은 형식으로 채웠다.

## 슬라이드 빌드
`python3 assets/tools/build_slides.py --both author-a/ep-04-3/slides.md` 실행 결과(rev12) 경고 0건. 본문 **13장**(cover·goal·result·chapter·big·two·steps·chapter·demo·demo·demo·chapter·wrap), 인트로·아웃트로 포함 15장. 챕터 3장(clock 6·17·2, AZ2로 이 절과 slides.md를 동기화 — 시연은 rev5 이후 16→17로 다시 올랐다가 그 값이 유지 중)·강사 노트 전체 슬라이드 보유·이론 슬라이드(big·two·steps) 대전·자치구·인물 0회 확인. **`src` 필드 4/4**(result·demo 999·demo 절대값·demo 타일지도) — HTML에서 `<div class="src">` 4건 재확인. chapter title·label 숫자 0건(AT2, 「79,957행」·「5개 구」 삭제).

## quiz 규격 확인
`assets/tools/build_quiz.py`의 `check()`·정답분포 로직을 재현해 자가 검사 — mc 5문항·open 1문항, 보기 4개씩, 정답 1~4, why·rubric 비어있지 않음. **AS2로 mc2 why의 축자 인용을 대본 현재 문장("유성구는 위쪽 묶음에서 아래쪽 묶음으로 내려갑니다")으로 교체** — `check_notes.py`의 신규 quiz why 자동 대조 재확인 결과 5/5 실재(stale 0). 인용 행(rev4 당시 L65·L69·L93·L96·L148·L150·L72·L74) 불변.

**rev17(건 17 PASS 뒤 quiz 단독 사전 검사, 숫자는 도구 출력을 그대로 — 손으로 다시 적지 않는다)**: 04-3은 PASS(태그 04-3-pass)했으나 빌더에 전략 4종(절대어 고르기·숫자 지우기 등)이 추가로 들어간 뒤 재실행하니 「찍기 기대 정답률」이 40%(절대어 고르기, mc3 정답에만 「예외 없이」가 있어서)로 관문(≤35%)을 넘었다 — script·slides는 그대로 두고 quiz.md만 고쳤다.
- mc3 정답의 「예외 없이」를 빼고(「일부러 넣어 둔」으로) 절대어 편중 해소.
- mc2 정답에 숫자(0.6%p)를 넣어 「숫자 지우기」 전략이 mc2를 배제하지 못하게 했다 — 다른 세 오답(1위·2위 언급 있음)과 길이도 22자로 맞춰 새 최장 편중은 만들지 않았다(quiz.md L23).
- 아래는 rev17 시점 `build_quiz.py` 실제 재실행 출력이다(가짜 openpyxl 스텁, 스크래치 폴더 사본 대상 — 집필자 폴더의 실제 xlsx는 손대지 않음).
```
정답 분포  1번 2(40%) 2번 1(20%) 3번 1(20%) 4번 1(20%)
정답이 유일 최장인 문항(길이 순위만)  1/5
번호 찍기(전 차시 합산 검사용)  최대 40%
영상 없이 찍기 기대 정답률(최대 전략)  최장 35.0%  [최장 35% · 길이1위 35% · 단정형 지우기 28% · 숫자 지우기 28% · 최단 25% · 길이2위 25% · 길이4위 25% · 절대어 지우기 25% · 절대어 고르기 25% · 길이3위 15% · 단정형 고르기 15% · 숫자 고르기 12%]
정답이 유일 최단인 문항  1/5
단정 서술 4계열(구조·배타·전면부정·빈도)  정답 0/5 · 오답 2/15
절대어 보기  정답 0/5 · 오답 0/15
정답 길이 순위 분포(1=최장)  1위 1 4위 1 동률 3
정답이 눈에 띄게 긴 보기  0/5 (0%)
```
경고 0건 — 「영상 없이 찍기 기대 정답률」 최댓값(최장 전략)이 정확히 0.35(35.0%)로 관문(>0.35) 아래. 번호 찍기 40%는 이 차시 5문항만으로는 구조적으로 못 피하는 값(2/5)이라 전 차시 합산에서만 본다는 도구 주석대로 이번 판정 대상이 아니다.

**rev18(PASS 유지, quiz 표면 특징 일반화 관문 대응)**: 빌더가 표면 특징(쉼표·따옴표·괄호·조건형·단정 어미·명사형 종결·글자 수·어절 수, 각각 최다/최소/있는/없는)을 전부 전략으로 일반화했다 — 재실행하니 「단정 어미 최소」 46.7%·「쉼표 최다」 45.0%로 새 관문(≤35%)을 다시 넘었다. mc3 정답만 "…이다" 없이 끝나고(다른 세 오답은 이다/있다로 끝남), mc2·mc4 정답에만 쉼표가 있어서였다. **실제 빌더 명령**(`uv run --with openpyxl --python 3.12 python assets/tools/build_quiz.py author-a/ep-04-3`)은 이 세션 샌드박스에서 네트워크 접근이 막혀 실행할 수 없었다 — `assets/tools/build_quiz.py`의 `check()`·전략 계산 로직을 그대로 복사해 스크래치에서 검증(가짜 openpyxl 스텁, 로직은 원본과 100% 동일, 산출물 없음)했고, Hans가 직접 위 명령으로 한 번 더 확인해 주길 요청한다.
- mc3 정답 "…결측 코드다" → "…결측 코드이다"로 어미를 맞춰 「단정 어미 최소」 편중 해소(다른 세 오답과 같은 어미 계열이 됨).
- mc2 정답의 쉼표를 빼고(rev18 당시 문구, rev19에서 단위 표기까지 다시 고쳤다), mc4 정답의 쉼표도 뺐다(「오늘 고른 분모인 인구 만명당 값」) — 「쉼표 최다」 편중 해소. 길이는 각각 22자·18자로 원래 값과 같게 맞춰 다른 지표를 새로 건드리지 않았다.
- 이 두 편집이 길이 순위를 흔들어 mc1·mc5 정답이 새로 "「길이 2위」 고르기"에 45%로 걸렸다 — mc1 정답에 "늘"(빈도 부사, 절대어 목록에는 없음)을 넣어 20자로, mc5 정답에서 "가"를 빼 20자로 맞춰 두 문항 모두 다른 보기와 길이가 동률이 되게 했다(quiz.md L12·L23·L30·L46).
- 재실행(로직 검증) 결과 최댓값 「단정 어미 최소」 31.7%로 관문 아래. 다른 지표(정답 길이 순위 「동률 5」, 유일 최장·최단 0/5, 4계열 0/5, 절대어 0/5)도 전부 안전권.
- script.md·slides.md는 손대지 않음(git status에 quiz.md만 변경으로 확인). notes.md 「quiz 규격 확인」에 재검증 결과 갱신.

**rev19(건 18 FAIL — 단위 오기·내용 왜곡 지적, PASS 유지)**: rev18에서 넣은 mc2 정답 「0.6%p차」가 단위 오기였다 — 512.7·509.6은 만명당 업소 수라 그 차이는 %p(퍼센트포인트)가 아니라 비율 0.6퍼센트다(대본·근거 절 표기와 통일). 「0.6퍼센트 차」로 정정. mc1 정답에 넣었던 「늘」도 대본 축자에 없는 강한 주장(빌더가 강조 부사 목록에 늘·자주·흔히·대개·보통·주로·거의를 추가로 넣은 뒤 걸릴 수 있었던 자리)이라 뺐다 — **관문을 맞추려고 정답 내용을 비트는 것은 금지, 정답 문장은 대본 축자의 뜻 그대로**라는 원칙을 재확인.
- mc1 정답을 원래 대본 축자 그대로("그 질문이 누구 단위로 일어나는가")로 되돌리고, 길이 균형은 정답이 아니라 **오답 두 개**(오답4를 "1등이 바뀌지 않을 분모를 고른다"로 재작성해 18자로 답과 동률)로 다시 맞췄다.
- mc2 정답을 "0.6퍼센트 차 아래쪽 묶음이라 꼴찌 모른다"(단위만 정정, 24자)로 바꾸고, 이번에도 길이 균형은 **오답**(오답1을 "1위로 올라가고 그 격차도 뚜렷하게 벌어진다"로 늘려 24자 동률)으로 맞췄다 — 정답 자체는 더 손대지 않음.
- 재실행(로직 검증, 가짜 openpyxl 스텁) 결과 최댓값 「단정 어미 최소」 31.7%로 관문 아래 유지, 「강조 부사」 계열도 전부 35% 아래(최소 28%가 최대). 다른 지표도 전부 안전권.
- script.md·slides.md는 손대지 않음. quiz.md L12·L15·L21·L23 정정.
- 아래는 rev19 시점 로직 검증(가짜 openpyxl 스텁) 실제 출력이다.
```
정답 분포  1번 2(40%) 2번 1(20%) 3번 1(20%) 4번 1(20%)
정답이 유일 최장인 문항(길이 순위만)  0/5
번호 찍기(전 차시 합산 검사용)  최대 40%
영상 없이 찍기 기대 정답률(최대 전략)  단정 어미(이다·된다·있다) 최소 31.7%
정답이 유일 최단인 문항  0/5
단정 서술 4계열(구조·배타·전면부정·빈도)  정답 0/5 · 오답 2/15
절대어 보기  정답 0/5 · 오답 0/15
정답 길이 순위 분포(1=최장)  동률 5
정답이 눈에 띄게 긴 보기  0/5 (0%)
```
경고 0건.
**rev11b(§0.14 절대어 분리 금지)**: `build_quiz.py`가 오답에만 절대어(항상·전부·반드시·미리·절대 등)가 몰리는지 새로 센다 — 재실행 결과 정답 0/5·오답 3/15 걸림(⚠). mc1 오답4 낱말 「미리」·mc4 오답1 낱말 「절대값」(부분 문자열 매치)·mc5 오답2 낱말 「항상」 세 곳을 각각 삭제·순화했다(mc4는 「절대」가 들어간 옛 표현을 「나눈 적 없는 업소 수 그 자체」로 바꿔 뜻은 그대로 두고 그 낱말만 뺐다) — 문항 의미·정답·오답 판정은 안 바뀜. 재실행(가짜 openpyxl 스텁) 결과 절대어 오답 0/15, 경고 0건. 다른 지표도 재확인: 정답 길이 순위 「1위1·4위2·동률2」(mc4 오답1 문구가 줄면서 mc5 오답2가 유일 최장으로 옮겨감, strict_longest 1/5 — 기준 ≤1/5 안), 오답평균비·편차·순위분포 전부 통과, 경고 0건 재확인. quiz.md L15·L39·L49 세 줄만 손댐, 인용 행(rev11b 당시 L65·L69·L93·L96·L148·L150·L72·L74)·why 텍스트는 불변.

**rev12(AZ5, §0.14 신설 — 정답이 유일 최단 ≤1/5)**: `build_quiz.py`가 정답이 4개 보기 중 유일하게 가장 짧은 문항 비율도 새로 센다(「절대」는 절대값 오탐 때문에 절대어 목록에서 빠졌다, AZ5 명시) — 재실행 결과 2/5(mc1·mc3) 걸림(⚠, 기준 ≤1/5). mc3(정답 24자, 최단)은 그대로 두고 mc1 오답3의 옛 26자 문구를 16자짜리로 줄여(quiz.md L14, rev16에서 다시 20자로 늘어남) mc1 정답(18자)이 더 이상 유일 최단이 아니게 했다 — 뜻은 그대로(데이터 사전에 있는 열을 무작정 고른다는 오류), 최장÷최단 비율도 32/16=2.0으로 상한 안(계약 ≤2.0 그대로 통과). 재실행 결과 유일 최단 1/5, 길이 순위 분포 「1위1·3위1·4위1·동률2」로 더 고르게 흩어짐, 경고 0건.

## 검사 로그 (rev19, 마지막 재실행 그대로 — 이 절은 도구 집계·검사 대상에서 제외됨. script·slides는 rev16과 동일, quiz만 정정)
```
$ python3 assets/tools/count_script.py author-a/ep-04-3/script.md
구간    라인                공백포함      공백제외    ÷250
도입    37-52              509       380     2.0
이론    53-79             1414      1048     5.7
시연    80-171            3468      2623    13.9
정리    172-189            396       296     1.6

합계 공백포함: 5787  ÷250 = 23.1 분
합계 공백제외: 4347  ÷250 = 17.4 분
drop log: {'heading': 4, 'screen': 11, 'boldhead': 0, 'comment': 0, 'fence': 2, 'blank': 66, 'paren': 52}

$ python3 assets/tools/build_slides.py --both author-a/ep-04-3/slides.md
author-a/ep-04-3/slides.html  슬라이드 15장 (인트로·아웃트로 포함) · 납품본 — 강사 노트 제외
author-a/ep-04-3/slides_notes.html  슬라이드 15장 (인트로·아웃트로 포함) · 강사용 — 노트 내장

$ python3 assets/tools/check_notes.py author-a/ep-04-3
이력 절 줄참조 검사 80개
script 내부 참조 검사 2개
검사 절 27개(검사 로그 절 제외) 중 검사 대상 줄 109 · 인용 24개 · 줄참조 46개 · stale 0
```
