Step 287. ★ CTF #5: 주력 분야 심화 확인전 — 우리의 천장이 어디인지 재는 대회
Level 3 — CTF 대회 사이클 | 난이도 ★★★★☆ | 예상 소요 시간 2일 (대회 참가 주말 + 사후 비교 분석)
전제: Step 284의 팀 약점 분석, Step 285의 약점 공략 대회. 주력 분야가 회의록에 합의되어 있어야 합니다.
- 준비물: CTFtime(
ctftime.org)에서 고른 주말 대회, 대회 #1~#4 결과 CSV, 아래에서 만들difficulty_stats.py, 팀 상태표. 대회 장면은 화면 예시, 난이도별 성공률 스크립트의 실행은 실측입니다(예시 데이터 사용). - ⚠️ 이 챕터의 실습은 내 랩·합법 플랫폼 전용입니다. 허가 없는 시스템에 적용하면 범죄입니다. 대회 문제 서버만이 공격 대상이며, 대회 인프라와 타 팀은 대상이 아닙니다. 종료 후 공개되는 상위 팀 Write-up은 배포된 출처에서만 읽습니다.
- 이 챕터는 대회 챕터입니다 — 약점을 메운(Step 285) 다음 판에는, 강점의 상한을 시험합니다.
Step 285에서 팀은 약점 분야의 문을 열었습니다. 이번에는 반대쪽입니다 — 잘하는 분야에서 우리가 어디까지 왔는가를 측정합니다. "주력 분야는 괜찮다"는 감으로는 팀의 체급을 모릅니다. 체급은 같은 분야 안에서 Easy는 놓치지 않는지, Medium을 얼마나 가져오는지, Hard의 문을 두드려 봤는지로만 잴 수 있습니다.
이 대회의 운영은 Step 285와 정확히 대칭입니다. 그때는 "기본 점수를 지키며 약점에 30%"였고, 오늘은 "기본 점수를 확보한 뒤 남은 시간의 절반을 주력 분야 Hard에" 투입합니다. 풀면 체급이 오르고, 못 풀어도 최고의 복기 재료 — 상위 팀 Write-up과의 비교 지점 — 가 생깁니다.
1. 학습 목표
이 챕터를 끝내면 다음을 할 수 있습니다:
- 같은 분야의 문제를 난이도별로 나눠 성공률을 측정해 "현재 체급"을 수치화한다
- 기본 점수 확보와 Hard 도전의 균형 룰을 설계하고 지킨다
- 2인 페어 프로그래밍(조사/코딩 분담)으로 Hard 문제를 공략한다
- 시간 종료 시 도달 지점을 문서화한다
- 상위 팀 Write-up과 자기 풀이를 비교해 "우리가 멈춘 곳에서 그들이 한 일"을 추출한다
2. 배경 지식 — 오늘의 도구와 개념
오늘의 도구 한눈에 보기
| 구분 | 내용 |
|---|---|
| 언어·환경 | CTFtime 주말 대회 (Jeopardy), 파이썬 3 (성공률 집계), 팀 상태표 |
| 오늘의 명령 | python difficulty_stats.py results.csv Web — 주력 분야 난이도별 성공률 |
| 필요한 개념 | 난이도별 성공률, Hard 도전 룰, 페어 프로그래밍, 도달 지점 비교 |
| 오늘의 산출물 | 난이도별 성공률 표 + Hard 문제 도달 지점 문서 + 상위 팀 비교 노트 |
2-1. 난이도별 성공률 — "어디까지 왔나"의 자
한 분야의 실력은 숫자 하나로는 잴 수 없습니다. 잴 것은 세 층입니다 — Easy 성공률(기초 체력), Medium 성공률(실전 체급), Hard 시도 여부(상한). 이 세 층의 조합이 팀의 현재 위치를 말합니다.
| 패턴 | 진단 |
|---|---|
| Easy 100% + Medium 50% + Hard 미시도 | 체급 상승 구간 — Hard에 문을 두드릴 때 |
| Easy 100% + Medium 100% + Hard 미시도 | 정체 위험 — 편안함이 성장을 막는 구간 |
| Easy 80% 미만 | 기초 재점검 — 상위 난이도 도전은 이르다 |
| Hard 시도 다수 + 성공 0 | 상한 근접 — 복기 비교가 가장 값진 구간 |
오늘 대회의 "확인전"이라는 이름은 이 표에서 나옵니다 — 대회는 시험이고, 시험 결과는 이 표의 갱신으로 남습니다.
2-2. Hard 도전 룰 — 순위 방어와 성장 도전의 균형
Hard 문제는 배점이 크지만 확률이 낮습니다. 팀 사기를 지키는 순서는 정해져 있습니다 — 먼저 기본 점수, 그다음 도전.
Hard 도전 룰 (시작 전 합의):
1. 대회 초반에 주력 분야 문제를 난이도 스캔 → Hard급 1개를 미리 지정
2. Easy·Medium으로 기본 점수를 확보한다 (팀 평균 성공률대로)
3. 기본 점수 확보 후, 남은 시간의 절반을 Hard에 투입
4. Hard 투입 시간은 "논스톱 몰입"이 아니라 30분 단위 진도 점검
1번이 핵심입니다 — Hard를 미리 지정해야 합니다. 대회 중반에 "이제 뭐 하지?" 하며 고른 Hard는 고른 것이 아니라 남은 것이고, 남은 Hard는 대개 팀과 안 맞는 문제입니다. 미리 지정하는 순간, Easy를 푸는 동안에도 뇌의 한구석이 Hard의 배경 조사를 합니다.
2-3. 페어 프로그래밍 — Hard는 혼자 풀지 않는다
Hard급 문제는 한 사람의 작업 기억 용량을 넘는 경우가 많습니다 — 조사할 것, 시도할 것, 기억할 것이 동시에 쏟아집니다. 그래서 2명이 한 화면으로 붙습니다.
| 역할 | 하는 일 |
|---|---|
| 드라이버(코딩) | 도구 실행, 스크립트 작성, 시도 — 손 |
| 내비게이터(조사) | 문서·치트시트·유사 기법 조회, 가설 추적, 진도 기록 — 눈과 기록 |
30분마다 역할을 바꿉니다. 이 규칙의 이유는 공정함이 아니라 사고의 교체입니다 — 같은 문제를 다른 역할에서 보면 보이는 것이 달라집니다. 그리고 내비게이터의 진도 기록이 그대로 오늘의 산출물(도달 지점 문서)이 됩니다.
2-4. 상위 팀 비교 — 멈춘 곳이 재료가 된다
Hard에 실패하는 것은 이 대회의 정상적인 결과이고, 실패가 남기는 것은 정확한 좌표입니다. 대회가 끝나고 상위 팀 Write-up이 올라오면, 비교는 한 문장으로 요약됩니다 — "우리가 멈춘 곳에서 그들은 무엇을 했는가."
이 비교가 값진 이유는 차이의 종류가 드러나기 때문입니다. 도구의 차이(우리에겐 없는 도구가 있었다), 지식의 차이(모르는 이론이 쓰였다), 사고의 차이(같은 단서를 다르게 읽었다). 도구 차이는 하루면 메워지고, 지식 차이는 학습 루트가 되고, 사고 차이는 가장 느리지만 가장 값진 복습 대상입니다.
3. 따라 하기
3-1. 대회 전 — 지난 데이터로 체급을 측정한다
대회 #1~#4의 결과 CSV(Step 284에서 만든 그 파일에 #4를 추가한 것)에서 주력 분야만 골라 난이도별 성공률을 뽑습니다. 아래 스크립트를 difficulty_stats.py로 저장하세요 — 코드와 출력은 예시 데이터로 실제 실행해 확인한 실측입니다.
# difficulty_stats.py — 주력 분야의 난이도별 성공률 측정 (확인전 채점표)
# 사용법: python difficulty_stats.py results.csv Web
import csv
import sys
from collections import defaultdict
def main(path, target):
rows = list(csv.DictReader(open(path, encoding="utf-8")))
rows = [r for r in rows if r["분야"] == target]
if not rows:
print(f"'{target}' 분야 데이터가 없습니다.")
return
# 난이도 × 대회 집계
cell = defaultdict(lambda: [0, 0]) # (난이도, 대회) -> [시도, 성공]
comps = sorted({r["대회"] for r in rows})
diffs = ["Easy", "Medium", "Hard"]
for r in rows:
c = cell[(r["난이도"], r["대회"])]
c[0] += int(r["시도"])
c[1] += int(r["성공"])
print(f"[{target} 분야 난이도별 성공률 — 대회별 추이]")
header = "| 난이도 | " + " | ".join(comps) + " | 합계 |"
print(header)
print("|" + "--------|" * (len(comps) + 2))
for d in diffs:
cols, ta, ts = [], 0, 0
for comp in comps:
att, suc = cell[(d, comp)]
ta, ts = ta + att, ts + suc
cols.append(f"{suc}/{att} ({suc / att * 100:.0f}%)" if att else "-")
total = f"{ts}/{ta} ({ts / ta * 100:.0f}%)" if ta else "-"
print(f"| {d} | " + " | ".join(cols) + f" | {total} |")
print("\n[읽는 법]")
for d in diffs:
att = sum(cell[(d, c)][0] for c in comps)
suc = sum(cell[(d, c)][1] for c in comps)
if att == 0:
print(f"- {d}: 시도 기록 없음 — 확인전에서 첫 시도가 필요합니다.")
else:
rate = suc / att * 100
note = "안정권" if rate >= 80 else "성장 구간" if rate >= 50 else "아직 벽"
print(f"- {d}: {suc}/{att} ({rate:.0f}%) — {note}")
if __name__ == "__main__":
main(sys.argv[1], sys.argv[2])
주력 분야가 Web인 예시 팀의 데이터(대회 #1~#5, Web 행만 추린 CSV)로 실행한 실측 결과입니다 — 이 출력에는 오늘 대회(CTF #5)의 결과까지 포함되어 있습니다. 여러분은 대회 전에 #4까지의 표를 먼저 뽑고, 대회 후에 #5를 추가해 다시 실행해 비교합니다.
python difficulty_stats.py results.csv Web
[Web 분야 난이도별 성공률 — 대회별 추이]
| 난이도 | CTF#1 | CTF#2 | CTF#3 | CTF#4 | CTF#5 | 합계 |
|--------|--------|--------|--------|--------|--------|--------|
| Easy | 2/2 (100%) | 2/2 (100%) | 2/2 (100%) | 2/2 (100%) | 2/2 (100%) | 10/10 (100%) |
| Medium | 0/1 (0%) | 0/1 (0%) | 0/1 (0%) | 1/2 (50%) | 2/2 (100%) | 3/7 (43%) |
| Hard | - | - | - | - | 0/1 (0%) | 0/1 (0%) |
[읽는 법]
- Easy: 10/10 (100%) — 안정권
- Medium: 3/7 (43%) — 아직 벽
- Hard: 0/1 (0%) — 아직 벽
읽는 법: 이 팀의 이야기가 읽힙니다 — Easy는 다섯 대회 연속 완벽, Medium은 #1~#3 전패에서 #4~#5로 오며 궤도에 올랐고, Hard는 오늘 처음 문을 두드렸습니다. 이 표가 있으면 "Web 잘하는 편 아니야?"라는 감 대신 "Easy 안정권, Medium 성장 구간 진입, Hard 첫 시도"라는 정확한 현재 위치를 말할 수 있습니다.
3-2. 대회 초반 — 난이도 스캔과 Hard 지정
시작 30분 안에 주력 분야 문제 전부를 훑고 난이도를 매깁니다. 대회가 매긴 점수가 기준이지만, 출제자의 난이도와 우리의 난이도는 다릅니다 — 치트시트와 겹치는가로 다시 재세요.
화면 예시:
Web 문제판 (5문제):
- cookie-jar (100) — 세션 변조, 치트시트 3번과 일치 → Easy
- jwt-kid (200) — kid 헤더 인젝션, 읽은 적 있음 → Easy~Medium
- ssrf-cloud (300) — 메타데이터 엔드포인트, #4에서 막힌 유형 → Medium
- race-auction (300) — 경쟁 상태, 복기한 적 있음 → Medium
- deser-chain (500) — 역직렬화 체인, 가젯 조립 필요 → Hard ★지정
Hard 지정의 근거를 한 줄로 남기세요 — "500점 최고 배점 + 역직렬화는 기초를 배운 유형 + 풀이 시간이 길 것." 지정 근거가 있어야 나중에 실패 원인 분석이 정확해집니다.
3-3. 대회 중반 — 기본 점수 확보, 그다음 Hard
Easy·Medium부터 가져갑니다. 순서를 어기고 Hard부터 붙잡는 것은 이 대회의 유일한 금기입니다 — 기본 점수 없는 Hard 도전은 도전이 아니라 도박이고, 실패했을 때 팀이 얻는 것이 아무것도 없습니다.
기본 점수가 확보되면 남은 시간의 절반을 Hard에 씁니다. 2-3의 페어로 붙고, 내비게이터는 30분마다 진도를 기록합니다.
화면 예시 (Hard 진도 기록):
[deser-chain 진도]
+0:30 엔드포인트 식별, 직렬화 포맷 확인 (PHP serialize 추정)
+1:00 입력 반영 지점 발견 — 로그 뷰어에서 역직렬화 호출 추정
+1:30 공개 가젯 체인 검색 — 프레임워크 버전 특정 실패
+2:00 로컬에 비슷한 환경 구성 시도 — 의존 버전 미스매치
+2:30 가젯 수동 조립 시작 — 첫 체인 후보 실패
+3:00 종료. 도달 지점: "가젯 조립 단계 진입, 체인 미완성"
3-4. 종료 직후 — 도달 지점 문서화
풀었든 못 풀었든, Hard 문제의 도달 지점을 문서로 남깁니다. 양식은 세 칸입니다.
### Hard 도달 지점 — deser-chain (CTF#5)
- 최종 도달: 가젯 조립 단계 (입력 → 역직렬화 확인 → 가젯 탐색 → 조립 실패)
- 시간 분배: 정찰 1h / 환경 구성 1h / 조립 1h
- 막힌 곳: 프레임워크 버전 특정 실패 → 공개 체인 적용 불가 → 수동 조립으로 전환했으나 시간 소진
이 문서의 가치는 3-5에서 폭발합니다. 기억이 아니라 기록이 있어야 비교가 정확합니다.
3-5. 사후 48시간 — 상위 팀 Write-up과 비교
대회 종료 후 Write-up이 올라오면, 도달 지점 문서를 펼쳐 놓고 읽습니다. 찾을 것은 하나 — 우리가 멈춘 곳에서 그들이 한 일.
화면 예시 (비교 노트):
[비교] deser-chain — 우리: 가젯 조립에서 정체 / 상위 팀 풀이와의 차이
- 그들의 행동: 버전 특정을 건너뛰고 에러 메시지에서 프레임워크 흔적을 읽었다
(500 응답의 스택 트레이스에 vendor 경로 노출 — 우리는 에러를 안 봤다)
- 차이의 종류: 사고의 차이 — "버전 특정 실패"를 벽으로 보지 않고 다른 정보원으로 전환
- 배운 것: 에러 응답은 실패 신호가 아니라 정보원 — 우리 치트시트 '함정' 칸에 추가
- 차이의 종류별 대응: 사고 차이 → 복기 블록 A에서 이 문제를 그들의 경로로 재현
비교 노트의 마지막 칸(종류별 대응)이 빠지면 읽기만 한 것입니다. 도구 차이는 도구를 설치하고, 지식 차이는 학습 루트를 정하고, 사고 차이는 그들의 경로로 재현합니다.
4. 미션과 연습문제
미션 — 주력 분야 확인전 완주
- 대회 전에
difficulty_stats.py로 주력 분야의 난이도별 성공률(대회 #1~#4)을 뽑고 현재 체급을 한 문장으로 적습니다. - 대회 초반에 주력 분야 문제의 난이도를 스캔하고 Hard급 1개를 근거와 함께 지정합니다.
- Easy·Medium 기본 점수를 먼저 확보한 뒤, 남은 시간의 절반을 Hard에 투입합니다 — 페어(조사/코딩)로, 30분 단위 진도 기록.
- 종료 직후 도달 지점 문서(최종 도달/시간 분배/막힌 곳)를 작성합니다.
- 대회 결과를 CSV에 추가하고 스크립트를 다시 실행해 성공률 표를 갱신합니다.
- 상위 팀 Write-up과 비교해 "우리가 멈춘 곳에서 그들이 한 일"과 차이의 종류별 대응을 정리합니다.
연습문제
문제 1. 주력 분야의 실력을 "총득점"이 아니라 난이도별 성공률 세 층(Easy/Medium/Hard)으로 재야 하는 이유는 무엇인가요?
문제 2. Hard 문제를 대회 초반에 "미리 지정"해야 하는 이유는 무엇인가요? 중반에 고르는 것과 무엇이 다른가요?
문제 3. Hard 도전 전에 기본 점수 확보를 먼저 하라는 룰이 팀 사기와 어떻게 연결되나요?
문제 4. 상위 팀과의 차이를 "도구/지식/사고" 세 종류로 나누는 이유는 무엇인가요? 각각의 대응은 무엇인가요?
5. 모범 답안과 완료 기준
미션 모범 답안
검증 기준으로 확인하세요.
- 사전 측정의 존재: 대회 전에 뽑은 성공률 표와 "현재 체급" 한 문장이 있는가 — 대회 후에만 표를 뽑으면 "확인전"이 아니라 그냥 대회입니다.
- Hard 지정의 근거: 지정 이유가 한 줄 이상 적혀 있는가 — 근거 없는 지정은 결과 분석의 기준선이 없는 것과 같습니다.
- 순서의 준수: 기본 점수 확보 후 Hard 투입이라는 순서가 진도 기록의 타임스탬프로 확인되는가.
- 도달 지점의 구체성: "아쉽게 못 풀었다"가 아니라 "어느 단계까지, 무엇에 막혔는가"가 명사형으로 적혔는가.
- 비교의 완결: 차이가 도구/지식/사고 중 어떤 종류로 분류됐고, 그에 맞는 대응(설치/학습/재현)이 정해졌는가.
연습문제 해답
문제 1 해답. 총득점은 출제 구성에 따라 요동치기 때문입니다 — Easy가 많이 나온 대회에서 점수가 높아도 실력이 오른 것이 아닙니다. 난이도별 성공률은 출제 구성의 영향을 걸러 낸 순수한 층위별 능력입니다. Easy 100%는 기초 체력, Medium 성공률은 실전 체급, Hard 시도는 상한을 각각 따로 말해 주고, 훈련도 그 층위별로 따로 설계됩니다.
문제 2 해답. 중반에 고른 Hard는 "고른 것이 아니라 남은 것"이기 때문입니다. 그 시점에는 이미 팀과 맞는 문제들이 배정되어, 남은 Hard는 흥미나 적성과 무관하게 선택됩니다. 반면 초반의 미리 지정은 치트시트와의 적합도, 배점, 예상 소요 시간을 비교해 고른 선택입니다. 그리고 지정 이후 Easy를 푸는 동안에도 뇌가 배경 조사를 진행하므로, 실제 투입 시간이 두둑해지는 부수 효과가 있습니다.
문제 3 해답. Hard는 실패 확률이 높은 슬롯이므로, 기본 점수 없이 실패하면 팀이 그 대회에서 손에 쥐는 것이 없기 때문입니다. "기본 확보 → 도전" 순서는 최악의 경우에도 점수와 도달 지점 문서를 남깁니다. 성장은 반복 가능해야 하고, 반복 가능하려면 팀이 "이 대회도 수확이 있었다"고 느껴야 합니다 — 사기는 결과 관리이지 감정 관리가 아닙니다.
문제 4 해답. 차이의 종류마다 메우는 비용과 방법이 다르기 때문입니다. 도구 차이는 설치하면 끝(하루), 지식 차이는 학습 루트로 메움(주 단위), 사고 차이는 그들의 경로로 재현하며 체화(가장 느리지만 가장 값짐). 종류를 분류하지 않으면 "열심히 하자"로 뭉개지고, 분류하면 각각에 맞는 구체 행동이 정해집니다. 복기의 산출물은 감상이 아니라 행동입니다.
완료 기준 체크리스트
- [ ] 대회 전에 주력 분야 난이도별 성공률 표를 뽑았다
- [ ] 현재 체급을 한 문장으로 적었다 (예: "Easy 안정권, Medium 성장 구간, Hard 미시도")
- [ ] Hard급 1개를 근거와 함께 미리 지정했다
- [ ] 기본 점수 확보 후 남은 시간의 절반을 Hard에 투입했다
- [ ] 페어(조사/코딩)로 공략하고 30분 단위 진도를 기록했다
- [ ] 도달 지점 문서(최종 도달/시간 분배/막힌 곳)를 작성했다
- [ ] 대회 결과를 반영해 성공률 표를 갱신했다
- [ ] 상위 팀 Write-up 비교 노트(차이의 종류+대응)를 완성했다
6. 흔한 실수와 해결
벽 1. 스크립트에 분야 이름을 넣었더니 "데이터가 없습니다"가 나와요
'web' 분야 데이터가 없습니다.
원인: CSV의 분야 값과 인자의 철자가 다릅니다. 이 스크립트는 대소문자를 구분합니다 — CSV가 Web인데 web으로 실행한 경우입니다.
해결: CSV 헤더 다음 행의 분야 칸을 그대로 복사해서 인자로 쓰세요. 분야 표기가 CSV 안에서부터 섞여 있다면(Web과 web이 공존), 먼저 CSV의 표기를 통일하세요 — 집계 도구의 정확도는 데이터의 일관성에서 나옵니다.
벽 2. Hard에 시간을 다 쓰고 기본 점수를 놓쳤어요
증상: 종료 후 정산해 보니 Easy 1개가 미시도. Hard는 실패.
원인: Hard의 몰입감이 룰을 삼켰습니다 — "조금만 더"의 반복. Hard급 문제는 진전이 있는 것처럼 느껴지는 함정 구간이 길어 특히 위험합니다.
해결: 30분 단위 진도 점검에 한 문장을 추가하세요 — "지금 Hard를 그만두고 Easy로 돌아가야 하는가?" 이 질문은 대회 중에는 스스로 하기 어렵습니다. 그래서 내비게이터의 임무로 못박습니다. 진도 기록은 Hard의 시간을 보호하는 도구이면서 동시에 Hard를 중단시키는 도구이기도 합니다.
벽 3. 페어가 하다 보니 한 사람만 계속 운전해요
증상: 드라이버가 3시간째 키보드를 잡고 있고, 내비게이터는 보고만 있습니다.
원인: 역할 교체 규칙을 안 지켰습니다. 몰입하면 교체 신호를 둘 다 못 듣습니다.
해결: 교체를 약속이 아니라 타이머로 만드세요 — 30분 알람이 울리면 키보드를 넘깁니다. 교체 직후 5분은 효율이 떨어지는 것이 정상입니다 — 그 5분이 새로운 눈의 비용이고, 그 눈이 발견하는 것이 Hard 공략의 실질입니다.
벽 4. 상위 팀 Write-up을 읽었는데 뭐가 다른지 모르겠어요
증상: "그냥 다 아는 사람이 쓴 것 같다"는 감상만 남습니다.
원인: 자기 팀의 도달 지점 문서 없이 읽었습니다. 비교는 두 점이 있어야 하는데, 한 점(우리의 멈춤)이 흐리면 읽기가 감상이 됩니다.
해결: 도달 지점 문서부터 다시 쓰세요 — 대회가 끝났어도 진도 기록(3-3)을 보면 복원됩니다. 그리고 읽는 순서를 바꿉니다 — 상위 팀 풀이를 처음부터 읽지 말고, 우리가 멈춘 단계에 해당하는 문단부터 찾아 읽습니다. 비교는 정독이 아니라 대조입니다.
벽 5. Hard를 못 풀어서 팀 분위기가 가라앉았어요
증상: "역시 우리 수준엔 무리였다"는 말이 나옵니다.
원인: 확인전의 목적을 착각했습니다. 이 대회는 Hard를 풀러 간 것이 아니라 천장의 위치를 재러 간 것입니다.
해결: 성공률 표를 다시 펼치세요 — Hard 행의 "-"가 "0/1"로 바뀐 것이 이번 대회의 결과물입니다. 시도가 없던 팀이 시도하는 팀이 됐고, 도달 지점이 문서로 남았고, 상위 팀과의 차이가 분류됐습니다. 천장은 재는 순간 깨지기 시작합니다 — 다음 대회의 Hard 행이 "0/2"든 "1/2"든, 그것이 성장의 눈금입니다.
7. 정리
오늘의 개념
| 개념 | 한 줄 설명 |
|---|---|
| 난이도별 성공률 | Easy(체력) / Medium(체급) / Hard(상한) — 총점이 못 말하는 것을 말하는 자 |
| 확인전 | 대회를 시험으로 쓰는 운영 — 결과는 성공률 표의 갱신으로 남는다 |
| Hard 도전 룰 | 기본 점수 먼저, 남은 시간의 절반, Hard는 미리 지정 |
| 페어 프로그래밍 | 드라이버(손) + 내비게이터(눈과 기록), 30분 교체 |
| 도달 지점 문서 | 최종 도달 / 시간 분배 / 막힌 곳 — 사후 비교의 기준점 |
| 차이의 3분류 | 도구 차이(설치) / 지식 차이(학습) / 사고 차이(재현) |
오늘의 도구·서식
| 도구·서식 | 하는 일 |
|---|---|
difficulty_stats.py |
CSV → 주력 분야 난이도별 성공률 표 + 진단 |
| 난이도 스캔 메모 | 출제자의 난이도를 우리의 난이도로 재는 절차 |
| Hard 진도 기록 | 30분 단위의 위치 표시 — 몰입의 감시 장치 |
| 도달 지점 문서 (3칸) | 실패를 좌표로 바꾸는 양식 |
| 비교 노트 | "우리가 멈춘 곳에서 그들이 한 일"의 추출 틀 |
명령어보다 중요한 감각
확인전의 산출물은 플래그가 아니라 눈금입니다. 성공률 표의 Hard 행에 첫 숫자가 찍힌 것, 도달 지점이 문장으로 남은 것, 상위 팀과의 차이가 "도구/지식/사고"로 분류된 것 — 이 세 개의 눈금이 팀의 천장을 보이게 합니다. 보이는 천장은 깨고 싶어지고, 깨고 싶은 천장은 훈련이 됩니다.
약점 공략(Step 285)이 지도를 넓히는 일이었다면, 확인전은 지도에 고도를 새기는 일입니다. 넓이와 고도를 다 재는 팀이 다음 단계 — 순위를 목표로 삼는 대회 — 에 갈 자격이 생깁니다. 그 자격은 점수가 아니라, 자기 위치를 숫자로 말할 수 있는 능력입니다.
전부 체크되면 Step 287 완료입니다. 사이드바의 체크박스를 눌러 진도를 저장하세요.