Files
aio-01d4-stu/Last3Mon/77/LAB-01-Q-READ-AND-MEASURE.md

45 KiB
Raw Permalink Blame History

Lab 01 · 실행 기록을 읽고, 지표로 만들기

  • 관련 강의: 1단계 · 실행 기록 읽기
  • 소요 시간: 50분 (2교시 한 시간) · 예제 1 10분 · 예제 2 15분 · 예제 3 7분 · 과제 1 8분 · 과제 2 10분
  • 준비: 실습 준비의 doctor → ready, 기준 보고서 base-report 게시
  • 목표: 두 주 동안의 실행 기록을 먼저 눈으로 읽고, 팀이 쓰던 기준 보고서의 숫자가 왜 다른지 찾는다. 같은 질문에 늘 같은 숫자로 답하는 지표 보고서를 만들고(지표는 정의가 먼저), 경계(하루 · 빈 기간 · 거르기)에서 재 보고, 날짜별 · 릴리스별 · 단계별 · 비용으로 나눠 본다.
flowchart LR
  E1["예제 1<br/>손으로 읽기 ·<br/>기준 보고서"] --> E2["예제 2<br/>지표 보고서"] --> E3["예제 3<br/>경계에서 재 보기"] --> T1["과제 1<br/>날짜별 · 릴리스별"] --> T2["과제 2<br/>단계별 · 비용"]

복사해 붙일 요청문은 없습니다. 막히면 ▶ 를 하나씩 펼칩니다. 연습이 끝나면 uv run tools/flow.py ops --reset.

시작하기 · 터미널 두 개

터미널 하는 일
① 에이전트 cd ~/aio-01d4-stu/Last3Mon/77 후 codex (또는 claude, agy). 내가 쓴 요청문을 보낸다
② 확인 cd ~/aio-01d4-stu/Last3Mon/77 에서 logs · call · push · test를 내가 실행한다

cp templates/OPS-ANALYSIS-TEMPLATE.md my-work/OPS.md 후 표를 채워 갑니다. 쓴 요청문은 my-work/PROMPTS.md에 모읍니다.

예제 1 · 손으로 읽기 · 팀의 기준 보고서 (10분, 에이전트 없이)

이 실습의 의도

한 줄로: 두 주 기록을 직접 훑어보고, 팀이 지난달 급히 만든 기준 보고서(base-report)에 같은 기간을 물어 두 숫자가 다른지 봅니다. 고치는 것은 예제 2부터이고, 여기서는 읽고 비교해 적기만 합니다.

생활 속 예 · 가게의 영수증 더미와 장부. 가게 계산대 옆에 두 주 치 영수증이 쌓여 있습니다. 사장님이 "두 주 동안 몇 건 팔았지?"라고 물으면, 알바생 둘이 서로 다른 답을 할 수 있습니다. 한 사람은 마지막 날 영수증을 빼고 셌고, 한 사람은 넣고 셌다면요. 예제 1은 영수증(실행 기록)을 직접 넘겨 보고, 팀 장부(기준 보고서)가 어떻게 셌는지 비교하는 실습입니다.

상황. 데이터 API에 IT 헬프데스크의 두 주(10/19~10/30, 평일 10일) 실행 기록 666줄이 있습니다. 한 줄이 헬프데스크가 질문 하나에 답한 한 번의 실행입니다. 팀에는 지난달 만든 보고서 워크플로우 base-report가 있고, 운영 회의에서 이 숫자를 써 왔습니다. 그런데 이 보고서가 맞는지 아무도 확인하지 않았습니다.

실험 넷.

실험 명령 볼 것
① 두 주를 훑기 logs --from 2026-10-19 --to 2026-10-30 실행 수 · 오류 수 · 갈래(route)마다 수, 마지막 다섯 줄
② 하루만 logs --from 2026-10-26 --to 2026-10-26 월요일 하루의 실행 · 오류 — 두 주의 오류와 비교
③ 기준에 두 주 call base-report requests/two-weeks.json ①과 같은 숫자인가? 어떤 칸이 있고 없나?
④ 기준에 하루 call base-report requests/monday.json ②와 같은가?

logs는 데이터 API의 기록을 그대로 세어 보여 주는 도구이고, base-report는 팀이 만든 워크플로우가 자기 방식으로 센 결과입니다. 둘이 다르면 어느 한쪽의 "세는 방법"이 다른 것입니다.

끝나면 알게 되는 것. 같은 기록이라도 무엇을 넣고 빼는지 · 무엇으로 나누는지 · 몇 자리로 끊는지에 따라 숫자가 달라집니다. 그것을 정해 둔 것이 지표의 정의이고, 예제 2에서 정의대로 다시 셉니다.

적을 곳. my-work/OPS.md 1.1 표 (질문 · 내 짐작 · 기준 보고서 · 다른 까닭).

# ① 두 주를 훑기
uv run tools/flow.py logs --from 2026-10-19 --to 2026-10-30 --last 5

# ② 하루만 (숫자만, --last 0)
uv run tools/flow.py logs --from 2026-10-26 --to 2026-10-26 --last 0

# ③ · ④ 팀의 기준 보고서에 같은 기간을
uv run tools/flow.py call base-report requests/two-weeks.json     # {"from": "2026-10-19", "to": "2026-10-30"}
uv run tools/flow.py call base-report requests/monday.json        # {"from": "2026-10-26", "to": "2026-10-26"}

이해하기

실행 기록 한 줄에 무엇이 있나. AGENTS.md 2절 "실행 기록 한 줄"입니다. 오늘 질문에 쓰는 칸은 이것뿐입니다.

칸 뜻 오늘 쓰는 곳
started_at 실행이 시작된 때 (2026-10-26T09:05:39) 기간 · 날짜별 · 시간대별
status success · error 오류 수 · 오류율
route 자동 답변 · 담당자 연결 · 잠시 후, 오류면 null 갈래별 · 답 못 함
duration_ms 한 실행에 걸린 시간 p50 · p95
error_node · error_message 오류가 난 노드 · 그 말 실패 묶음 (Lab 02)
topic · release · repeat 질문 주제 · 버전 · 10분 안에 다시 물음 릴리스별 · 다시 묻는 주제
steps · cost_usd · llm_calls 단계마다 시간 · 비용 · LLM 호출 수 과제 2

지표는 "정의 + 계산"입니다. "오류율"이라는 말만으로는 숫자가 하나로 정해지지 않습니다. 기간의 끝날을 넣나? 0.0315로 쓰나 3.15로 쓰나? 몇 자리에서 끊나? 느린 정도는 평균인가 p95인가? 이것을 미리 정해 둔 것이 정의이고, 정의가 같아야 지난주와 이번 주, 내 숫자와 옆 사람 숫자를 비교할 수 있습니다.

flowchart LR
  L[("실행 기록 666줄")] --> A["logs<br/>그대로 셈"]
  L --> B["base-report<br/>팀의 방식으로 셈"]
  A --> C{"같은 숫자?"}
  B --> C
  C -->|다르면| D["세는 방법(정의)이<br/>어디서 다른가"]

기대 결과. logs의 두 주 · 하루 숫자와 기준 보고서의 숫자가 다릅니다. 어느 칸이 왜 다른지 OPS.md 1.1에 적습니다. 무엇이 다른지는 아래 실행 결과를 보기 전에 먼저 찾아 봅니다.

▶ 1단계 · 두 숫자가 다르면 무엇부터 보나

차이가 얼마인지 봅니다. 두 주 666과 기준의 숫자의 차이가 어느 하루의 실행 수와 같다면? logs --from 2026-10-30 --to 2026-10-30 --last 0으로 확인해 봅니다.

▶ 2단계 · 기준의 오류율은 무엇으로 나눴나

logs는 오류율을 3.2%로 보여 줍니다. 기준의 error_rate는 어떤 모양인가요? 백분율인가 비율인가, 몇 자리인가? 하루만 물었을 때의 null은 무엇을 0으로 나눈 것일까요?

실행 결과 · 손으로 읽기 · 기준 보고서

수업 준비 때(10/31) 강사 노트북에서 실제로 나온 출력입니다. 두 주 기록은 바뀌지 않으므로 숫자는 누가 돌려도 같습니다 (call의 시간만 다름).

이 예제는 고치지 않습니다. 같은 기간을 logs(그대로 셈)와 기준 보고서(팀의 방식)에 물어 비교합니다. 고치는 것은 예제 2입니다.

① · ② logs로 두 주 · 하루

실행한 명령:

uv run tools/flow.py logs --from 2026-10-19 --to 2026-10-30 --last 5
uv run tools/flow.py logs --from 2026-10-26 --to 2026-10-26 --last 0

출력:

666 run(s) · errors 21 (3.2%)
  route: 자동 답변 591 · 담당자 연결 34 · 오류 21 · 잠시 후 20
  2026-10-30T17:05:38  success 자동 답변   1311ms  프린터    인쇄 대기열이 안 비워져요
  2026-10-30T17:11:46  success 자동 답변   1175ms  메일    메일함 용량이 꽉 찼대요
  2026-10-30T17:20:51  success 담당자 연결    79ms  와이파이    회의실 와이파이가 안 잡혀요
  2026-10-30T17:24:39  success 자동 답변   1205ms  메일    첨부 파일이 너무 커서 안 보내져요
  2026-10-30T17:59:20  success 자동 답변   1076ms  메일    메일함 용량이 꽉 찼대요

70 run(s) · errors 16 (22.9%)
  route: 자동 답변 50 · 오류 16 · 담당자 연결 4

왜 이렇게 나왔나

  • 두 주 666건 중 오류 21건(3.2%). 그런데 하루(10/26 월요일)에 16건이 몰려 있습니다. 그날의 오류율은 22.9%로, 두 주 평균의 7배쯤입니다. "두 주 동안 오류율 3%"라는 말만으로는 이 사실이 보이지 않습니다.
  • 마지막 다섯 줄은 10/30(금) 저녁의 실행입니다. 담당자 연결 한 줄(와이파이, 79ms)이 눈에 띕니다. 답을 찾지 못해 바로 사람에게 넘긴 실행입니다 (Lab 02).

③ · ④ 기준 보고서에 같은 기간

실행한 명령:

uv run tools/flow.py call base-report requests/two-weeks.json
uv run tools/flow.py call base-report requests/monday.json

출력:

HTTP 200 · 1.2s
{ "total": 602, "errors": 21, "error_rate": 3.488372093023256, "avg_ms": 1249.2392026578073,
  "by_route": { "자동 답변": 529, "담당자 연결": 32, "잠시 후": 20 } }

HTTP 200 · 0.1s
{ "total": 0, "errors": 0, "error_rate": null, "avg_ms": null, "by_route": {} }

왜 이렇게 나왔나

칸 logs 기준 보고서 다른 까닭
두 주 실행 666 602 666 − 602 = 64 = 10/30 하루의 실행. 기준은 started_at < to로 걸러 끝날을 뺐습니다 (2026-10-30T09:…는 2026-10-30보다 큰 글자)
오류율 3.2% (0.0315) 3.488… 백분율(×100)이고, 끊지 않았고, 분모가 602
느린 정도 (p95는 예제 2) 평균 1249.2ms 평균만 있음. 대부분이 겪는 시간을 말하지 못함
오류로 끝난 실행 갈래 오류 21 갈래에 없음 route가 null인 줄을 건너뜀. 갈래를 더하면 581 ≠ 602
하루 (from = to) 70 · 오류 16 0 · null 끝날을 빼니 하루를 물으면 아무것도 남지 않고, 0을 0으로 나눠 null
  • 기준 보고서는 "고장"이 아닙니다. 200을 주고, 숫자도 그럴듯합니다. 세는 방법이 다를 뿐인데, 운영 회의에서는 이 숫자로 "두 주에 602건"이라고 말해 왔습니다.
  • 이 차이를 OPS.md 1.1에 적습니다. 예제 2에서 정의를 정하고, 예제 3에서 경계를 더 재 봅니다.

예제 2 · 지표 보고서 (15분)

이 실습의 의도

한 줄로: 예제 1에서 본 차이를 없애기 위해, AGENTS.md 3절 정의대로 세는 내 보고서(my-log-report)를 만듭니다. Lab 01의 중심 실습이고, 오늘 만드는 모든 것이 이 보고서를 바탕으로 합니다.

생활 속 예 · 가게의 장부 쓰는 법. 알바생마다 세는 법이 다르면 장부를 믿을 수 없습니다. 그래서 가게는 "마감일 영수증도 넣는다, 금액은 원 단위까지, 환불도 따로 적는다"처럼 장부 쓰는 법을 벽에 붙여 둡니다. 예제 2는 그 쓰는 법(정의)을 요청문에 그대로 넣어, 누가 만들어도 같은 숫자가 나오는 보고서를 만드는 실습입니다.

예제 1에서 본 것 정의 (AGENTS.md 3절) 확인하는 케이스
마지막 날이 빠짐 날짜는 포함 (from ≤ 날짜 ≤ to, 데이터 API가 거름) 두 주 · 첫 주 · 둘째 주 · 하루
오류율이 백분율 · 끊지 않음 errors / total, 소수 4자리, 0건이면 0 두 주 · 둘째 주
평균만 있음 p50_ms · p95_ms = 오름차순 ceil(p × n)번째 두 주 · 둘째 주
오류가 갈래에 없음 route가 null이면 "오류" 두 주 · 갈래별

순서. 같은 테스트를 기준에 먼저 돌려 0/5를 봄 (케이스마다 무엇이 틀렸는지) → 요청문을 써서 에이전트가 새 파일을 만들게 함 → push → 5/5.

끝나면 알게 되는 것. 정의를 요청문에 적으면 에이전트도 같은 숫자를 낸다는 것, p95가 평균과 어떻게 다른지, 숫자는 LLM이 아니라 Code가 세야 하는 까닭.

만들 것: 기간(from · to)을 받아 실행 기록을 가져와 지표를 계산해 돌려주는 워크플로우.

uv run tools/flow.py test cases/lab01.json --webhook base-report -v     # 고치기 전 (기준에 같은 테스트)
조건 값
파일 · 웹훅 my-work/log-report.json (새로) · my-log-report
지표 total, errors, error_rate, p50_ms, p95_ms, by_route — 정의는 AGENTS.md 3절
계산 Code 노드 하나 (LLM 없음)
기대 결과 cases/lab01.json (두 주 · 갈래별 · 첫 주 · 둘째 주 · 하루)

이해하기

지금 무엇이 문제인가. 기준 보고서는 틀린 계산을 한 것이 아니라 다른 정의로 셌습니다. 그래서 고치는 일은 "버그 찾기"보다 "정의를 정해 그대로 세기"입니다. 정의가 요청문에 없으면 에이전트도 자기 방식(평균, 보간한 p95, 백분율…)으로 셉니다.

flowchart LR
  subgraph 기준
    A1(["from · to"]) --> B1["로그 전체를 가져와<br/>started_at < to 로 거름"] --> C1["평균 · 백분율<br/>오류 갈래 없음"]
  end
  subgraph 내 보고서
    A2(["from · to · tag · source"]) --> B2["데이터 API가 거름<br/>(날짜 포함)"] --> C2["Code: 정의대로<br/>p50 · p95 · 소수 4자리 · 오류 갈래"]
  end

p95란. 실행 시간을 짧은 것부터 줄 세웠을 때 95%째에 있는 값입니다. "100명 중 95명은 이 시간 안에 답을 받았다"는 뜻입니다. 오늘 정의는 가장 가까운 순위(nearest-rank)입니다: n개를 오름차순으로 놓고 ceil(0.95 × n)번째. 예를 들어 값이 10개면 ceil(9.5) = 10번째, 666개면 ceil(632.7) = 633번째입니다. 평균은 아주 느린 몇 건에 끌려가고, 대부분의 사용자가 겪는 시간을 말하지 못합니다.

같은 기록 평균 p50 p95
1초 × 9건 + 10초 × 1건 1.9초 1초 10초

왜 Code인가. LLM에게 666줄을 주고 "오류율이 얼마야?"라고 물으면 틀릴 수 있고(세는 일은 LLM이 약함), 줄이 많을수록 돈이 듭니다 (75일차). 숫자는 Code가 정확하게, 빠르게(0.1초 안팎) 셉니다. LLM은 Lab 02 과제 2에서 센 결과를 글로 설명할 때만 씁니다.

테스트 케이스.

케이스 보내는 것 기대
두 주 전체 two-weeks total 666 · errors 21 · error_rate 0.0315 · p50_ms 1205 · p95_ms 2537
두 주 · 갈래별 two-weeks 자동 답변 591 · 담당자 연결 34 · 잠시 후 20 · 오류 21
첫 주 week1 309 · 0 · 0
둘째 주 week2 357 · 21 · 0.0588 · p95 2598
10월 26일 하루 monday 70 · 16

기대 결과. 고치기 전(기준에 같은 테스트) 0/5, 고친 뒤 5/5.

▶ 1단계 · 정의를 요청문에

"p95를 구해 줘"만 쓰면 에이전트마다 계산이 다릅니다 (평균? 보간?). 3절의 정의를 그대로 요청문에 넣거나 "AGENTS.md 3절 정의대로"라고 씁니다. 반올림 자리, 0건일 때도.

▶ 2단계 · 거르기는 누가

기간 · tag · source로 거르는 일은 데이터 API(POST /logs/query)가 합니다 (AGENTS.md 2절). 워크플로우는 웹훅 본문을 그대로 넘기면 됩니다. 기준처럼 다 가져와서 직접 거르면 정의가 두 곳에 생깁니다.

▶ 빈칸 채우기 · 요청문(프롬프트) 뼈대

요청문에 꼭 들어갈 것: ① 파일 · 웹훅 ② 넘길 본문과 기본값 ③ 지표와 정의(반올림 · 0건) ④ 백분위 정의 ⑤ LLM 없음 · 기대 결과. 아래 빈칸 4개(____①~____④)를 채워 my-work/PROMPTS.md에 쓴 뒤 에이전트에게 보냅니다.

my-work/log-report.json 을 새로 만들어 줘. 웹훅 POST ____①, 이름 "77 Log report (my)".
Get logs(HTTP POST http://data-api:8800/logs/query) 에 웹훅 본문의 from · to · tag · source 를 넘기고, source 가 없으면 ____②.
Compute metrics(Code) 하나에서 AGENTS.md 3절 정의대로 total · errors · error_rate · p50_ms · p95_ms · by_route 를 계산해 줘.
error_rate 는 errors / total 을 소수 ____③자리 반올림, 0건이면 0.
p50 · p95 는 duration_ms 를 오름차순으로 놓고 ____④번째 값 (1부터 셈, 오류 실행도 포함). route 가 null 이면 by_route 의 "오류".
LLM 은 쓰지 않는다. 기대 결과 cases/lab01.json.

빈칸 힌트 (답이 아니라 어디서 찾고 무엇을 생각하나):

  • ① AGENTS.md 3절 계약 표의 "로그 보고서" 줄입니다. 테스트 파일 cases/lab01.json 맨 위의 webhook과 같아야 합니다.
  • ② source의 세 값(all · seed · live) 중, 요청에 source가 없을 때 두 주 기록과 오늘 기록을 모두 보는 값.
  • ③ 3절 지표 표의 error_rate 줄. 테스트의 기대값 0.0315를 보면 몇 자리인지 보입니다.
  • ④ 3절 지표 표의 p50_ms · p95_ms 줄의 굵은 글씨입니다. 위 "p95란"의 예와 같이.

채운 요청문은 수업 뒤 공개되는 정답본의 요청문 예와 비교합니다.

uv run tools/flow.py push my-work/log-report.json
uv run tools/flow.py test cases/lab01.json -v
uv run tools/flow.py call my-log-report requests/week2.json

실행 결과 · 지표 보고서

수업 준비 때(10/31) 강사 노트북에서 정답 워크플로우로 실제로 나온 출력입니다. 지표 숫자는 두 주 기록을 정의대로 센 것이라 누구에게나 같고, 시간만 조금씩 다릅니다.

고치기 전 · 기준(base-report)에 같은 테스트

실행한 명령:

uv run tools/flow.py test cases/lab01.json --webhook base-report -v

출력 (결과 줄만, -v의 요청 · 응답은 줄임):

✘ 두 주 전체 · 0.2s · total = 602 (expected 666); error_rate = 3.488372093023256 (expected 0.0315); p50_ms = null (expected 1205); p95_ms = null (expected 2537)
✘ 두 주 · 갈래별 · 0.1s · by_route.자동 답변 = 529 (expected 591); by_route.담당자 연결 = 32 (expected 34); by_route.오류 = null (expected 21)
✘ 첫 주 · 0.1s · total = 245 (expected 309)
✘ 둘째 주 · 0.1s · total = 293 (expected 357); error_rate = 7.167235494880546 (expected 0.0588); p95_ms = null (expected 2598)
✘ 10월 26일 하루 · 0.1s · total = 0 (expected 70); errors = 0 (expected 16)
Passed 0/5

왜 이렇게 나왔나 (고치기 전)

  • total이 모두 작음: 602 · 245 · 293 · 0. 기간마다 끝날의 실행 수만큼 빠졌습니다 (첫 주 309 − 245 = 64 = 10/23, 둘째 주 357 − 293 = 64 = 10/30). 하루를 물으면 끝날이 곧 그날이라 0입니다.
  • error_rate가 3.488… · 7.167…: 백분율에, 반올림이 없고, 분모도 줄어든 total입니다. 기대값 0.0315는 "비율, 소수 4자리"입니다.
  • p50_ms · p95_ms가 null: 기준에는 그런 칸이 없습니다 (avg_ms만). null은 "그 칸이 없음"입니다.
  • by_route.오류가 null: 오류로 끝난 실행을 갈래에서 건너뛰었습니다. 자동 답변 529 · 담당자 연결 32도 끝날이 빠진 만큼 작습니다.
  • 0/5는 예상한 결과입니다. 다섯 케이스의 ✘가 모두 예제 1에서 찾은 정의의 차이 넷으로 설명됩니다.

고친 뒤 · 내 my-log-report

실행한 명령:

uv run tools/flow.py push my-work/log-report.json
uv run tools/flow.py test cases/lab01.json -v
uv run tools/flow.py call my-log-report requests/week2.json

출력 (결과 줄과 call):

✔ 두 주 전체 · 0.9s
✔ 두 주 · 갈래별 · 0.1s
✔ 첫 주 · 0.2s
✔ 둘째 주 · 0.1s
✔ 10월 26일 하루 · 0.0s
Passed 5/5

HTTP 200 · 0.1s
{ "total": 357, "errors": 21, "error_rate": 0.0588, "p50_ms": 1171, "p95_ms": 2598,
  "by_route": { "오류": 21, "자동 답변": 299, "담당자 연결": 17, "잠시 후": 20 } }

고친 뒤 이렇게 나온 까닭

케이스 고치기 전 (기준) 고친 뒤 무엇이 바꿨나
두 주 실행 602 666 거르기를 데이터 API에 맡김 (날짜 포함)
두 주 오류율 3.488… 0.0315 errors / total, 소수 4자리
두 주 p50 · p95 없음 1205 · 2537ms 오름차순 ceil(p × n)번째
오류 갈래 없음 21 null → "오류"
하루 0 70 · 오류 16 끝날 포함
  • 둘째 주 응답을 읽으면: 357건 중 오류 21, 오류율 0.0588(5.88%). 갈래를 더하면 21 + 299 + 17 + 20 = 357로 total과 맞습니다. 기준에서는 맞지 않던 합입니다.
  • p50 1171 · p95 2598: 절반은 1.2초 안에, 95%는 2.6초 안에 답을 받았습니다. 첫 주 p95(2525)와 비교하면 조금 느려졌습니다. 평균 하나로는 이런 비교가 어렵습니다.
  • 0.1초 안팎: 666줄을 Code 하나에서 셌습니다. LLM은 부르지 않았습니다.
  • 이제 이 보고서가 오늘의 기준 숫자입니다. 과제 · Lab 02 · Lab 03은 모두 이 파일에 칸을 더해 갑니다.

예제 3 · 경계에서 재 보기 (7분, 에이전트 없이)

이 실습의 의도

한 줄로: 예제 2의 내 보고서와 기준 보고서에 경계의 질문(하루만 · 빈 기간 · 주말 · 기간 없음 · source)을 같이 던져, 평소에는 안 보이던 정의의 차이를 드러냅니다. 고치는 실습이 아니라 재 보는 실습입니다.

생활 속 예 · 줄자의 눈금 끝. 줄자로 1m를 잴 때 "끝 눈금을 넣나"는 보통 상관없어 보입니다. 하지만 1cm짜리를 재면 그 한 칸이 전부입니다. 장부도 그렇습니다. 두 주를 셀 때는 그럴듯하던 장부가 "오늘 하루" · "손님이 없던 날"을 물으면 0이나 오류를 냅니다. 예제 3은 끝 눈금처럼 작은 경계에서 두 장부를 재 보는 실습입니다.

상황. 보통 기간(두 주 · 한 주)에서는 기준 보고서도 그럴듯한 숫자를 냅니다. 그런데 운영에서는 "오늘 하루만", "이번 주 아직 0건", "오늘 실습 기록만"처럼 경계의 질문을 자주 합니다. 같은 테스트 cases/lab01-edges.json을 두 보고서에 돌립니다.

경계 보내는 것 기대 (정의대로)
하루 · from = to monday 70건 · 오류 16 (끝날 포함)
빈 기간 11/02~11/06 (기록 없음) 200 · total 0 · error_rate 0 · p95_ms 0
주말 10/24~10/25 0건
기간을 비우면 {} 666 (전체)
source: seed 두 주 · 두 주 기록만 666
source: live 오늘 실습 기록만 (아직 없음) 0 · 오류율 0

끝나면 알게 되는 것. 정의는 경계에서 시험받는다는 것, 0으로 나누기 · 끝날 포함 · 거르기를 처음부터 정해 둬야 한다는 것. 그리고 테스트에 경계 케이스를 넣는 까닭.

적을 곳. my-work/OPS.md 1.2 표 (경계 · 내 보고서 · 기준 보고서 · 기준이 틀린 까닭).

uv run tools/flow.py test cases/lab01-edges.json -v                       # 내 보고서
uv run tools/flow.py test cases/lab01-edges.json --webhook base-report    # 같은 케이스를 기준에

이해하기

경계(edge)란. 값의 범위 끝에 있는 경우입니다: 0건, 1일, 첫날 · 마지막 날, 거르기를 했을 때 아무것도 남지 않는 경우. 프로그램의 실수는 대부분 경계에서 나옵니다. 보통 경우만 시험하면 "잘 된다"고 믿게 됩니다.

경계 정의가 없으면 생기는 일
끝날 <와 ≤의 차이로 하루가 통째로 빠짐
0건 0 / 0 → NaN → JSON의 null (화면에 빈칸, 다음 계산이 깨짐)
거르기 source · tag를 무시하면 늘 전체가 나옴 (오늘 실습 기록만 보고 싶어도)

--webhook base-report. 같은 케이스 파일을 다른 웹훅에 돌리는 옵션입니다. 테스트 파일은 그대로 두고 두 워크플로우를 비교할 때 씁니다.

기대 결과. 내 보고서 6/6. 기준 보고서는 대부분 ✘ — 어느 케이스가 왜 ✘인지가 이 예제의 답입니다.

▶ 1단계 · `source: live`에 기준이 666을 낸다면

기준 보고서가 데이터 API에 무엇을 보내는지 봅니다: uv run tools/flow.py diff reference/baseline-report.json my-work/log-report.json. Get logs 노드의 본문을 비교해 보세요.

실행 결과 · 경계에서 재 보기

수업 준비 때(10/31) 강사 노트북에서 실제로 나온 출력입니다.

이 예제는 고치지 않습니다. 같은 케이스 파일을 내 보고서와 기준 보고서에 돌려 비교합니다. 기준을 고치지 않는 것은, 오늘은 기준과 비교하는 연습이기 때문입니다.

내 보고서 (my-log-report)

실행한 명령:

uv run tools/flow.py test cases/lab01-edges.json -v

출력 (결과 줄만):

✔ before: POST http://localhost:8800/logs-reset · HTTP 200 · 0.0s · {"cleared": 0}
✔ 하루 · from = to (포함) · 0.0s
✔ 빈 기간 · 0건이어도 200 · 0.1s
✔ 주말 · 실행이 없는 날 · 0.0s
✔ 기간을 비우면 전체 · 0.1s
✔ source seed · 두 주 기록만 · 0.0s
✔ source live · 오늘 실습 기록 (아직 없음) · 0.0s
Passed 6/6

왜 이렇게 나왔나: 첫 줄 before는 테스트가 먼저 오늘 실습 기록을 비운 것입니다 (live가 0이어야 하므로). 내 보고서는 거르기를 데이터 API에 맡기고, 0건이면 나누지 않으므로 경계에서도 정의대로입니다. 빈 기간 · 주말은 total 0 · error_rate 0 · p95_ms 0으로 200을 줍니다.

같은 케이스를 기준에 (base-report)

실행한 명령:

uv run tools/flow.py test cases/lab01-edges.json --webhook base-report

출력:

✘ 하루 · from = to (포함) · 0.1s · total = 0 (expected 70); errors = 0 (expected 16)
✘ 빈 기간 · 0건이어도 200 · 0.1s · error_rate = null (expected 0); p95_ms = null (expected 0)
✔ 주말 · 실행이 없는 날 · 0.1s
✔ 기간을 비우면 전체 · 0.0s
✘ source seed · 두 주 기록만 · 0.1s · total = 602 (expected 666)
✘ source live · 오늘 실습 기록 (아직 없음) · 0.1s · total = 666 (expected 0); error_rate = 3.153153153153153 (expected 0)
Passed 2/6

왜 이렇게 나왔나 (케이스마다)

경계 기준의 결과 까닭
하루 0건 started_at < to로 끝날을 뺌 → 하루를 물으면 그날이 통째로 빠짐
빈 기간 오류율 · p95 null 0 / 0 = NaN → JSON으로 null. p95 칸은 원래 없음
주말 ✔ 0건 실행이 없는 날이라 어떻게 세도 0 — 우연히 맞음
기간 없음 ✔ 666 거를 것이 없으면 끝날 문제도 없음 — 역시 우연
source: seed 602 source는 맞았지만 끝날 문제가 그대로
source: live 666 · 3.15… 기준은 Get logs에 늘 {source: 'all'}만 보내고 본문의 source를 무시. 오늘 기록만 묻는데 두 주 전체를 셈
  • 기준이 맞은 두 케이스(주말 · 기간 없음)는 정의가 맞아서가 아니라 경계가 문제를 가려서 맞았습니다. 보통 경우만 시험하면 이렇게 "잘 된다"고 믿게 됩니다.
  • source: live의 666은 Lab 03에서 위험합니다. "고친 뒤 오늘 기록만" 보려고 해도 두 주 전체를 보게 되기 때문입니다. 경계 케이스를 테스트에 넣어 두면 이런 일을 미리 막습니다.

과제 1 · 날짜별 · 릴리스별 (8분)

이 실습의 의도

한 줄로: 두 주 합계를 날짜로 나눠 오류가 언제 몰렸는지 보고, 릴리스로 나눠 새 버전의 답이 도움이 됐는지(다시 묻는 비율) 봅니다.

생활 속 예 · 가계부의 월 합계와 날짜별 칸. 한 달 지출이 늘었다는 것만으로는 무엇을 줄일지 모릅니다. 날짜별 칸을 보면 "15일에 한 번 크게 썼다"가 보입니다. 새로 바꾼 장보기 앱도 "그 앱으로 산 날만" 따로 봐야 좋아졌는지 압니다. 과제 1은 보고서에 날짜별 칸과 버전별 칸을 더하는 실습입니다.

팀장이 요청했습니다.

"둘째 주에 오류가 늘었다는데, 매일 그런 건지 어느 날만 그런 건지 알고 싶어요. 그리고 지난주에 새 버전(1.1.0)과 카나리(1.2.0)를 내보냈잖아요. 버전마다 사람들이 같은 걸 다시 묻는 비율도 봐 주세요."

조건 값
날짜별 by_day — 날짜마다 total · errors · error_rate, 날짜순 (AGENTS.md 3절)
릴리스별 by_release — 자동 답변인 실행만, 릴리스마다 answers · repeats · repeat_rate (3절)
기대 결과 cases/lab01-challenge.json, lab01.json도 그대로

먼저 생각해 보기 (2분): 다시 묻는 비율을 왜 자동 답변인 실행만으로 셀까요? 1.2.0은 몇 건이었나요 — 그 비율을 믿어도 될까요?

uv run tools/flow.py test cases/lab01-challenge.json -v     # 고치기 전

이해하기

묶어서 세기(group by). 같은 칸(날짜, 릴리스)의 값이 같은 줄끼리 모아 각각 셉니다. 오늘 보고서의 지표 대부분은 "무엇으로 묶고, 무엇을 세고, 무엇으로 나누나"의 세 가지로 정해집니다.

지표 묶는 칸 세는 것 나누는 것
by_day started_at 앞 10자 실행 · 오류 그날 실행
by_release release (자동 답변만) 답 · 다시 물음 그 릴리스의 답

분모를 고르는 일. "다시 묻는 비율"의 분모가 전체 실행이면, 답을 못 한 실행(담당자 연결 · 오류)도 들어가 버전의 답의 질과 상관없는 것이 섞입니다. 답을 준 실행만 분모로 해야 "그 버전의 답이 도움이 됐나"를 잽니다.

표본 크기. 1.2.0은 카나리(일부 사용자만)라 답이 8건뿐입니다. 8건 중 5건이면 62.5%지만, 몇 건만 달라져도 크게 바뀝니다. 비율 옆에는 늘 건수를 같이 봅니다 (74일차 카나리).

기대 결과. 고치기 전 0/6, 고친 뒤 6/6. 10/26은 70건 중 오류 16, 날짜는 평일 10일.

▶ 1단계 · 날짜순으로

묶은 결과는 객체({"2026-10-19": {...}, ...})입니다. 키를 정렬해서 만들면 화면에도 날짜순으로 나옵니다.

▶ 빈칸 채우기 · 요청문(프롬프트) 뼈대

요청문에 꼭 들어갈 것: ① 묶는 칸 ② 거르는 조건(자동 답변만) ③ 세는 것 ④ 앞의 지표를 두기. 아래 빈칸 4개를 채워 my-work/PROMPTS.md에 쓴 뒤 에이전트에게 보냅니다.

my-work/log-report.json 의 Compute metrics 에 by_day 와 by_release 를 더해 줘.
by_day: started_at 앞 ____①자(날짜)로 묶어 {"2026-10-26": {total, errors, error_rate}}, 날짜순.
by_release: route 가 "____②" 인 실행만 release 로 묶어 {answers, repeats, repeat_rate}.
repeats 는 repeat 가 ____③ 인 수, repeat_rate = repeats / answers (소수 4자리).
앞의 지표는 ____④ 둔다. 기대 결과 cases/lab01-challenge.json, cases/lab01.json 도.

빈칸 힌트:

  • ① started_at(2026-10-26T09:05:39)에서 날짜까지가 몇 글자인지 셉니다.
  • ② route의 세 값 중 "답을 준" 갈래입니다.
  • ③ AGENTS.md 2절 repeat의 값 중 "다시 물었다"는 쪽.
  • ④ 같은 파일에 더하는 것이라 예제 2의 지표를 어떻게 하나요? lab01 5/5를 지켜야 합니다.
uv run tools/flow.py push my-work/log-report.json
uv run tools/flow.py test cases/lab01-challenge.json -v
uv run tools/flow.py test cases/lab01.json

실행 결과 · 날짜별 · 릴리스별

수업 준비 때(10/31) 강사 노트북에서 실제로 나온 출력입니다.

고치기 전 · 예제 2의 보고서

실행한 명령:

uv run tools/flow.py test cases/lab01-challenge.json -v

출력 (결과 줄만):

✘ 날짜별 · 월요일 · 0.1s · by_day.2026-10-26.total = null (expected 70); by_day.2026-10-26.errors = null (expected 16); by_day.2026-10-26.error_rate = null (expected 0.2286)
✘ 날짜별 · 목요일 · 0.1s · by_day.2026-10-29.total = null (expected 97); by_day.2026-10-29.errors = null (expected 5)
✘ 날짜는 10일 · 0.1s · by_day has none of ['"2026-10-19"']
✘ 릴리스별 다시 묻기 · 1.2.0 · 0.1s · by_release has none of ['"1.2.0": {"answers": 8, "repeats": 5, "repeat_rate": 0.625}']
✘ 릴리스별 다시 묻기 · 1.0.0 · 1.1.0 · 0.1s · by_release has none of ['"1.0.0": {"answers": 402, "repeats": 19, "repeat_rate": 0.0473}']
✘ 1.1.0 · 0.1s · by_release has none of ['"1.1.0": {"answers": 181, "repeats": 14, "repeat_rate": 0.0773}']
Passed 0/6

왜 이렇게 나왔나 (고치기 전)

  • 예제 2의 보고서에는 by_day · by_release 칸이 아직 없습니다. 날짜 케이스는 null, 릴리스 케이스는 찾을 글자가 없다(has none of)고 합니다.
  • 릴리스 케이스가 equals가 아니라 글자 찾기(contains)인 까닭: 키 1.2.0에 점이 있어 by_release.1.2.0.answers처럼 내려갈 수 없습니다. 그래서 JSON 글자 "1.2.0": {"answers": 8, …}를 통째로 찾습니다 (AGENTS.md 7절).
  • 0/6은 예상한 결과입니다.

고친 뒤

실행한 명령:

uv run tools/flow.py push my-work/log-report.json
uv run tools/flow.py test cases/lab01-challenge.json -v
uv run tools/flow.py test cases/lab01.json

출력 (결과 줄만):

✔ 날짜별 · 월요일 · 1.0s
✔ 날짜별 · 목요일 · 0.1s
✔ 날짜는 10일 · 0.2s
✔ 릴리스별 다시 묻기 · 1.2.0 · 0.1s
✔ 릴리스별 다시 묻기 · 1.0.0 · 1.1.0 · 0.1s
✔ 1.1.0 · 0.0s
Passed 6/6
(lab01 5/5)

고친 뒤 이렇게 나온 까닭

볼 것 값 읽는 법
10/26 (월) 70건 · 오류 16 · 0.2286 두 주 오류 21건 중 16건이 이날
10/29 (목) 97건 · 오류 5 나머지 5건은 목요일
날짜 평일 10일 (10/24 · 25 없음) 주말에는 실행이 없음
1.0.0 답 402 · 다시 물음 19 · 4.73% 기준 버전
1.1.0 답 181 · 다시 물음 14 · 7.73% 새 버전 — 다시 묻는 비율이 올랐음
1.2.0 (카나리) 답 8 · 다시 물음 5 · 62.5% 비율은 높지만 8건뿐
  • 팀장의 첫 질문 "매일 그런가, 어느 날만 그런가"의 답: 월요일 하루(16건)와 목요일(5건)입니다. 둘째 주 다른 날에는 오류가 없습니다. 어느 시간인지는 Lab 02 예제 2에서 봅니다.
  • 둘째 질문 "버전마다 다시 묻는 비율"의 답: 1.1.0이 1.0.0보다 높고(7.73% > 4.73%), 1.2.0은 62.5%지만 8건으로는 판단하기 이릅니다. 비율과 함께 건수(answers)를 꼭 보고합니다.
  • 1.0.0 + 1.1.0 + 1.2.0의 답 = 402 + 181 + 8 = 591 = 두 주 자동 답변 수. 분모를 "답을 준 실행"으로 정했으니 맞습니다.
  • lab01 5/5: 같은 파일에 칸을 더했지만 앞의 지표는 그대로입니다.

과제 2 · 어느 단계가 느린가 · 얼마 들었나 (10분)

이 실습의 의도

한 줄로: 실행 전체의 p95만으로는 어디가 느린지 모릅니다. 단계(FAQ 검색 · LLM 답)마다 시간을 재고, 두 주 동안 LLM에 얼마를 썼는지(비용 · 실행당 비용 · 호출 수)를 보고서에 더합니다.

생활 속 예 · 택배의 구간별 시간. 택배가 늦었다고 화내기 전에 배송 조회를 보면 "집하 → 허브 → 배송" 구간마다 시간이 찍혀 있습니다. 허브에서 하루를 묵었다면 기사님을 재촉해도 소용없습니다. 과제 2는 헬프데스크의 한 번의 실행을 구간(단계)으로 나눠 재고, 택배비(LLM 비용)도 함께 적는 실습입니다.

운영팀이 물었습니다.

"p95가 2.5초쯤인데, FAQ 검색이 느린 건가요 LLM이 느린 건가요? 그리고 두 주에 LLM 비용이 얼마나 들었는지, 한 번에 얼마쯤인지도요."

조건 값
단계별 steps.faq_ms · steps.answer_ms — 그 단계 값이 0보다 큰 실행만, {runs, p50, p95} (AGENTS.md 3절)
비용 cost_usd(합, 소수 5자리) · cost_per_run(실행당, 소수 6자리) · llm_calls(합)
기대 결과 cases/lab01-challenge2.json, lab01 · lab01-challenge도 그대로

먼저 생각해 보기 (2분): 잠시 후로 끝난 실행은 FAQ도 LLM도 거치지 않아 두 단계 모두 0ms입니다. 이 실행들을 단계 p50에 넣으면 무슨 일이 생길까요?

uv run tools/flow.py test cases/lab01-challenge2.json -v     # 고치기 전

이해하기

단계(step) 시간. 한 실행의 duration_ms는 여러 단계의 합입니다. 오늘 헬프데스크는 faq_ms(FAQ 검색)와 answer_ms(LLM 답)를 기록합니다. 전체가 느릴 때 어느 단계가 늘었는지 보면 고칠 곳이 정해집니다 (72일차 timeout, 75일차 비용).

flowchart LR
  Q(["질문"]) --> F["FAQ 검색<br/>faq_ms"] --> A{{"LLM 답<br/>answer_ms"}} --> R(["답"])
  F -.->|없음| N["담당자 연결<br/>answer_ms 0"]

거치지 않은 단계는 뺀다. 잠시 후(20건)는 두 단계 모두 0, 담당자 연결(34건)은 답 단계가 0입니다. 0을 넣으면 "빠른 실행"처럼 보여 단계의 진짜 시간이 작게 나옵니다. 그래서 단계마다 값이 0보다 큰 실행만 모으고, 몇 건을 모았는지(runs)도 함께 씁니다.

기간을 나누면 다른 문제가 보인다. 두 주 전체의 FAQ 단계 p95는 작지만, 하루만 떼어 보면 다를 수 있습니다. 케이스에 "월요일 · FAQ 단계가 느림"이 있는 까닭입니다.

비용. 기록마다 cost_usd(그 실행의 LLM 비용)가 있습니다. 합은 두 주 예산을, 실행당 비용은 "질문 하나에 얼마"를 말합니다 (75일차 비용 · 예산). 0건이면 나누지 않고 0.

기대 결과. 고치기 전 0/5, 고친 뒤 5/5. 테스트 줄 끝에 596 calls · $0.078360처럼 보이는 것은 응답의 llm_calls · cost_usd를 flow.py가 함께 보여 주는 것입니다.

▶ 1단계 · 백분위 함수를 다시 쓰기

예제 2의 p50 · p95 계산(오름차순 · ceil(p × n)번째)을 단계 값에도 그대로 씁니다. 같은 정의를 두 번 쓰지 말고 같은 함수를 부르게 요청합니다.

▶ 빈칸 채우기 · 요청문(프롬프트) 뼈대

요청문에 꼭 들어갈 것: ① 단계 값을 모으는 조건 ② 비용 반올림 ③ 호출 수 ④ 앞의 테스트. 아래 빈칸 4개를 채워 my-work/PROMPTS.md에 쓴 뒤 에이전트에게 보냅니다.

my-work/log-report.json 의 Compute metrics 에 steps 와 비용을 더해 줘.
steps: faq_ms · answer_ms 마다, steps 의 그 값이 ____① 실행만 모아 {runs, p50, p95} (백분위 정의는 앞과 같음, 없으면 runs 0 · p50 0 · p95 0).
cost_usd: 실행마다 cost_usd 의 합, 소수 ____②자리 반올림. cost_per_run: cost_usd / total, 소수 6자리 (0건이면 0).
llm_calls: 실행마다 llm_calls 의 ____③.
앞의 지표는 그대로. 기대 결과 cases/lab01-challenge2.json, ____④ 도 그대로 통과.

빈칸 힌트:

  • ① 위 "먼저 생각해 보기"의 답입니다. 거치지 않은 단계의 값은 얼마로 기록되나요?
  • ② 3절의 cost_usd 줄. 기대값 0.07836의 자리 수를 셉니다.
  • ③ 실행마다 llm_calls는 0 또는 1입니다. 두 주 전체로는?
  • ④ 같은 파일을 고쳤으니 다시 돌려 볼 테스트 두 개.
uv run tools/flow.py push my-work/log-report.json
uv run tools/flow.py test cases/lab01-challenge2.json -v
uv run tools/flow.py test cases/lab01.json
uv run tools/flow.py test cases/lab01-challenge.json

실행 결과 · 단계별 · 비용

수업 준비 때(10/31) 강사 노트북에서 실제로 나온 출력입니다.

고치기 전 · 과제 1까지의 보고서

실행한 명령:

uv run tools/flow.py test cases/lab01-challenge2.json -v

출력 (결과 줄만):

✘ 두 주 · 단계별 p95 · 0.1s · steps.faq_ms.p95 = null (expected 39); steps.answer_ms.p95 = null (expected 2509); steps.answer_ms.p50 = null (expected 1179)
✘ 두 주 · 단계마다 잰 실행 수 · 0.1s · steps.faq_ms.runs = null (expected 646); steps.answer_ms.runs = null (expected 596)
✘ 월요일 · FAQ 단계가 느림 · 0.1s · steps.faq_ms.p95 = null (expected 1000); steps.answer_ms.p95 = null (expected 2482)
✘ 두 주 · 비용 · 0.1s · cost_usd = null (expected 0.07836); cost_per_run = null (expected 0.000118); llm_calls = null (expected 596)
✘ 빈 기간 · 비용 0 · 0.0s · cost_usd = null (expected 0); cost_per_run = null (expected 0); llm_calls = null (expected 0); steps.faq_ms.p95 = null (expected 0)
Passed 0/5

왜 이렇게 나왔나 (고치기 전)

  • steps · cost_usd · cost_per_run · llm_calls 칸이 아직 없어 모두 null입니다. 기록 한 줄에는 steps와 cost_usd가 있지만, 보고서가 아직 세지 않았습니다.
  • 0/5는 예상한 결과입니다.

고친 뒤

실행한 명령:

uv run tools/flow.py push my-work/log-report.json
uv run tools/flow.py test cases/lab01-challenge2.json -v
uv run tools/flow.py test cases/lab01.json
uv run tools/flow.py test cases/lab01-challenge.json

출력 (결과 줄만):

✔ 두 주 · 단계별 p95 · 0.9s · 596 calls · $0.078360
✔ 두 주 · 단계마다 잰 실행 수 · 0.1s · 596 calls · $0.078360
✔ 월요일 · FAQ 단계가 느림 · 0.2s · 50 calls · $0.006450
✔ 두 주 · 비용 · 0.1s · 596 calls · $0.078360
✔ 빈 기간 · 비용 0 · 0.0s · 0 calls · $0.000000
Passed 5/5
(lab01 5/5 · lab01-challenge 6/6)

고친 뒤 이렇게 나온 까닭

볼 것 두 주 월요일만 읽는 법
FAQ 단계 p95 39ms (646건) 1000ms 평소 FAQ는 빠름. 월요일에는 timeout(1초)에 걸린 실행이 p95를 차지
답 단계 p50 · p95 1179 · 2509ms (596건) p95 2482ms 평소 느린 것은 LLM 답 단계
비용 0.07836달러 0.00645달러 두 주 LLM 비용
실행당 비용 0.000118달러 질문 하나에 약 0.0001달러
LLM 호출 596 50 답을 준 실행마다 한 번
  • 운영팀 질문의 답: 평소 p95 2.5초의 대부분은 LLM 답 단계(p95 2509ms)입니다. FAQ 검색은 39ms입니다. 그런데 월요일만 떼어 보면 FAQ 단계 p95가 1000ms — 그날은 FAQ 검색이 문제였습니다. 같은 지표도 기간을 나누면 다른 고칠 곳이 보입니다 (Lab 02 · 03).
  • runs 646 · 596: FAQ 단계는 잠시 후 20건을 뺀 646건, 답 단계는 답을 준 591건 + 답 도중 실패한 5건 = 596건입니다. 0인 값을 넣었다면 단계 p50이 작게 나왔을 것입니다.
  • 테스트 줄 끝의 596 calls · $0.078360: 응답에 llm_calls · cost_usd가 생기자 flow.py가 함께 보여 주는 것입니다 (75일차 기능). 빈 기간은 0 calls · $0.000000.
  • lab01 5/5 · lab01-challenge 6/6: 앞의 지표는 그대로입니다.

막혔을 때

증상 할 일
total이 맞지 않음 Get logs가 웹훅 본문의 from · to를 넘기는지 (직접 거르지 않음), source 기본값이 all인지
p95_ms가 1~2 다름 오름차순 · ceil(p × n)번째(1부터 셈) · 오류 실행도 포함하는지
error_rate가 0.03149… 소수 4자리 반올림
빈 기간에 null 0건이면 나누지 않고 0
by_route.오류가 없음 route가 null인 실행을 "오류"로
by_release를 equals로 못 찾음 키에 점(1.2.0)이 있어 케이스는 contains로 JSON 글자를 찾음 — 모양을 정확히 {"answers", "repeats", "repeat_rate"} 순서로
단계 p50이 너무 작음 0인 단계 값을 뺐는지
계속 안 됨 cp reference/lab01-example2-report.json my-work/log-report.json 후 push (예제 2까지)

확인

  • 예제 1: OPS.md 1.1 (내 짐작 · 기준 보고서 · 다른 까닭).
  • 예제 2: cases/lab01.json 5/5 (고치기 전 기준에 0/5).
  • 예제 3: cases/lab01-edges.json 내 보고서 6/6, 기준이 ✘인 까닭을 OPS.md 1.2에.
  • 과제 1: cases/lab01-challenge.json 6/6, lab01도 통과.
  • 과제 2: cases/lab01-challenge2.json 5/5, lab01 · lab01-challenge도 통과, OPS.md 2절.
  • my-work/PROMPTS.md.