> **정답 자료** · 77일차 n8n 워크플로우를 **만드는 프롬프트(codex) → push → `call` · `test -v` · `logs` · `ops` 결과**를 학생이 가는 순서대로 한 문서에 모았습니다. 수업이 끝난 뒤 공개합니다.
- 실행: 2026-10-31, 실습을 Lab마다 5개(예제 3 + 과제 2)로 늘린 뒤 강사 노트북의 65일차 n8n 2.42.6 + 77일차 판 데이터 API(76일차 + 두 주 실행 기록 666줄 · 오늘 실습 기록 · FAQ 더하기), OpenAI `gpt-4.1-mini`(요약 · 헬프데스크 답), 케이스 파일마다 **한 번씩**, 모두 26단계 (00~25)
- 명령: `~/aio-01d4-stu/Last3Mon/77`에서 `uv run tools/flow.py ...`. 아래 단계마다 **실행한 명령**과 **화면에 나온 출력 전부**를 그대로 붙이고, 그 아래 **쉽게 말하면**으로 결과를 풀어 썼습니다 (특히 ✘가 나온 까닭과 그것이 예상한 것인지). 같은 출력이 `NN-<이름>.txt`에, 그 단계 첫 `test`의 보고서가 `NN-<이름>.json`에 있습니다 (00 · 01단계는 보고서 없음).
- 지표는 두 주 기록을 정의대로 계산한 값이라 **늘 같습니다.** 실행마다 다른 것은 시간, LLM 요약 글, 오늘 실습 기록의 단계 시간(ms)뿐입니다. 이번 실행에서 정답의 잘못으로 실패한 케이스는 없습니다. ✘는 모두 "고치기 전" 단계에서 본 것입니다.
- "고치기 전" 상태: 00단계에서 `my-*` 워크플로우를 모두 **게시 해제**(`off`)하고 `ops --reset`으로 오늘 기록 · 더한 FAQ를 비워 학생이 처음 여는 상태와 같게 했습니다.
## `-v`가 보여 주는 것
```text
✔ 둘째 주 · 0.1s ← 케이스 · 시간
→ request POST /webhook/my-log-report ← 보낸 요청 JSON
- 두 주: FAQ 단계 p95 **39ms**(646건), 답 단계 p50 1179 · p95 **2509ms**(596건) — 평소 느린 것은 LLM 답 단계입니다.
- 월요일만: FAQ 단계 p95가 **1000ms** — timeout(1초)에 걸린 실행이 p95를 차지했습니다. 같은 지표도 기간을 나누면 다른 문제가 보입니다.
- 비용: 두 주 0.07836달러, 실행당 0.000118달러, LLM 호출 596번. 빈 기간은 모두 0. 테스트 줄 끝의 `596 calls · $0.078360`은 응답의 `llm_calls` · `cost_usd`를 flow.py가 보여 준 것입니다 (75일차 기능).
-`lab01` 5/5 · `lab01-challenge` 6/6 그대로. 예상한 결과.
## Lab 02 · 문제를 숫자로 찾고, 요약하기
### 09 · Lab 02 하기 전 → `lab02` 0/6
실행한 명령:
```bash
uv run tools/flow.py test cases/lab02.json -v
```
출력 (그대로):
```text
POST http://localhost:5678/webhook/my-log-report · 6 case(s) × 1
POST http://localhost:5678/webhook/my-log-report · 5 case(s) × 1
✔ 두 주 · 다시 묻는 비율이 가장 높은 주제 · 0.9s · 596 calls · $0.078360
→ request POST /webhook/my-log-report
{
"from": "2026-10-19",
"to": "2026-10-30"
}
← response HTTP 200
{
"total": 666,
"errors": 21,
"error_rate": 0.0315,
"p50_ms": 1205,
"p95_ms": 2537,
"by_route": {
"자동 답변": 591,
"담당자 연결": 34,
"오류": 21,
"잠시 후": 20
},
"by_day": {
"2026-10-19": {
"total": 73,
"errors": 0,
"error_rate": 0
},
"2026-10-20": {
"total": 57,
"errors": 0,
"error_rate": 0
},
"2026-10-21": {
"total": 60,
"errors": 0,
"error_rate": 0
},
"2026-10-22": {
"total": 55,
"errors": 0,
"error_rate": 0
},
"2026-10-23": {
"total": 64,
"errors": 0,
"error_rate": 0
},
"2026-10-26": {
"total": 70,
"errors": 16,
"error_rate": 0.2286
},
"2026-10-27": {
"total": 62,
"errors": 0,
"error_rate": 0
},
"2026-10-28": {
"total": 64,
"errors": 0,
"error_rate": 0
},
"2026-10-29": {
"total": 97,
"errors": 5,
"error_rate": 0.0515
},
"2026-10-30": {
"total": 64,
"errors": 0,
"error_rate": 0
}
},
"by_release": {
"1.0.0": {
"answers": 402,
"repeats": 19,
"repeat_rate": 0.0473
},
"1.1.0": {
"answers": 181,
"repeats": 14,
"repeat_rate": 0.0773
},
"1.2.0": {
"answers": 8,
"repeats": 5,
"repeat_rate": 0.625
}
},
"steps": {
"faq_ms": {
"runs": 646,
"p50": 27,
"p95": 39
},
"answer_ms": {
"runs": 596,
"p50": 1179,
"p95": 2509
}
},
"cost_usd": 0.07836,
"cost_per_run": 0.000118,
"llm_calls": 596,
"failures": [
{
"node": "Search FAQ",
"message": "timeout of 1000ms exceeded",
"count": 16
},
{
"node": "Answer",
"message": "429 Rate limit reached for requests",
"count": 5
}
],
"unanswered_topics": [
{
"topic": "와이파이",
"count": 34
}
],
"anomalies": [
{
"hour": "2026-10-26T09",
"total": 16,
"errors": 16,
"error_rate": 1
},
{
"hour": "2026-10-29T15",
"total": 7,
"errors": 5,
"error_rate": 0.7143
}
],
"repeat_topics": [
{
"topic": "프린터",
"answers": 81,
"repeats": 8,
"repeat_rate": 0.0988
},
{
"topic": "비밀번호",
"answers": 139,
"repeats": 9,
"repeat_rate": 0.0647
},
{
"topic": "VPN",
"answers": 124,
"repeats": 8,
"repeat_rate": 0.0645
},
{
"topic": "접수 현황",
"answers": 96,
"repeats": 6,
"repeat_rate": 0.0625
},
{
"topic": "메일",
"answers": 90,
"repeats": 5,
"repeat_rate": 0.0556
},
{
"topic": "설치",
"answers": 61,
"repeats": 2,
"repeat_rate": 0.0328
}
]
}
✔ 두 주 · 수로는 비밀번호가 가장 많지만 비율은 2위 · 0.3s · 596 calls · $0.078360
→ request POST /webhook/my-log-report
{
"from": "2026-10-19",
"to": "2026-10-30"
}
← response HTTP 200
{
"total": 666,
"errors": 21,
"error_rate": 0.0315,
"p50_ms": 1205,
"p95_ms": 2537,
"by_route": {
"자동 답변": 591,
"담당자 연결": 34,
"오류": 21,
"잠시 후": 20
},
"by_day": {
"2026-10-19": {
"total": 73,
"errors": 0,
"error_rate": 0
},
"2026-10-20": {
"total": 57,
"errors": 0,
"error_rate": 0
},
"2026-10-21": {
"total": 60,
"errors": 0,
"error_rate": 0
},
"2026-10-22": {
"total": 55,
"errors": 0,
"error_rate": 0
},
"2026-10-23": {
"total": 64,
"errors": 0,
"error_rate": 0
},
"2026-10-26": {
"total": 70,
"errors": 16,
"error_rate": 0.2286
},
"2026-10-27": {
"total": 62,
"errors": 0,
"error_rate": 0
},
"2026-10-28": {
"total": 64,
"errors": 0,
"error_rate": 0
},
"2026-10-29": {
"total": 97,
"errors": 5,
"error_rate": 0.0515
},
"2026-10-30": {
"total": 64,
"errors": 0,
"error_rate": 0
}
},
"by_release": {
"1.0.0": {
"answers": 402,
"repeats": 19,
"repeat_rate": 0.0473
},
"1.1.0": {
"answers": 181,
"repeats": 14,
"repeat_rate": 0.0773
},
"1.2.0": {
"answers": 8,
"repeats": 5,
"repeat_rate": 0.625
}
},
"steps": {
"faq_ms": {
"runs": 646,
"p50": 27,
"p95": 39
},
"answer_ms": {
"runs": 596,
"p50": 1179,
"p95": 2509
}
},
"cost_usd": 0.07836,
"cost_per_run": 0.000118,
"llm_calls": 596,
"failures": [
{
"node": "Search FAQ",
"message": "timeout of 1000ms exceeded",
"count": 16
},
{
"node": "Answer",
"message": "429 Rate limit reached for requests",
"count": 5
}
],
"unanswered_topics": [
{
"topic": "와이파이",
"count": 34
}
],
"anomalies": [
{
"hour": "2026-10-26T09",
"total": 16,
"errors": 16,
"error_rate": 1
},
{
"hour": "2026-10-29T15",
"total": 7,
"errors": 5,
"error_rate": 0.7143
}
],
"repeat_topics": [
{
"topic": "프린터",
"answers": 81,
"repeats": 8,
"repeat_rate": 0.0988
},
{
"topic": "비밀번호",
"answers": 139,
"repeats": 9,
"repeat_rate": 0.0647
},
{
"topic": "VPN",
"answers": 124,
"repeats": 8,
"repeat_rate": 0.0645
},
{
"topic": "접수 현황",
"answers": 96,
"repeats": 6,
"repeat_rate": 0.0625
},
{
"topic": "메일",
"answers": 90,
"repeats": 5,
"repeat_rate": 0.0556
},
{
"topic": "설치",
"answers": 61,
"repeats": 2,
"repeat_rate": 0.0328
}
]
}
✔ 두 주 · 다시 물은 주제는 6개 · 0.1s · 596 calls · $0.078360
→ request POST /webhook/my-log-report
{
"from": "2026-10-19",
"to": "2026-10-30"
}
← response HTTP 200
{
"total": 666,
"errors": 21,
"error_rate": 0.0315,
"p50_ms": 1205,
"p95_ms": 2537,
"by_route": {
"자동 답변": 591,
"담당자 연결": 34,
"오류": 21,
"잠시 후": 20
},
"by_day": {
"2026-10-19": {
"total": 73,
"errors": 0,
"error_rate": 0
},
"2026-10-20": {
"total": 57,
"errors": 0,
"error_rate": 0
},
"2026-10-21": {
"total": 60,
"errors": 0,
"error_rate": 0
},
"2026-10-22": {
"total": 55,
"errors": 0,
"error_rate": 0
},
"2026-10-23": {
"total": 64,
"errors": 0,
"error_rate": 0
},
"2026-10-26": {
"total": 70,
"errors": 16,
"error_rate": 0.2286
},
"2026-10-27": {
"total": 62,
"errors": 0,
"error_rate": 0
},
"2026-10-28": {
"total": 64,
"errors": 0,
"error_rate": 0
},
"2026-10-29": {
"total": 97,
"errors": 5,
"error_rate": 0.0515
},
"2026-10-30": {
"total": 64,
"errors": 0,
"error_rate": 0
}
},
"by_release": {
"1.0.0": {
"answers": 402,
"repeats": 19,
"repeat_rate": 0.0473
},
"1.1.0": {
"answers": 181,
"repeats": 14,
"repeat_rate": 0.0773
},
"1.2.0": {
"answers": 8,
"repeats": 5,
"repeat_rate": 0.625
}
},
"steps": {
"faq_ms": {
"runs": 646,
"p50": 27,
"p95": 39
},
"answer_ms": {
"runs": 596,
"p50": 1179,
"p95": 2509
}
},
"cost_usd": 0.07836,
"cost_per_run": 0.000118,
"llm_calls": 596,
"failures": [
{
"node": "Search FAQ",
"message": "timeout of 1000ms exceeded",
"count": 16
},
{
"node": "Answer",
"message": "429 Rate limit reached for requests",
"count": 5
}
],
"unanswered_topics": [
{
"topic": "와이파이",
"count": 34
}
],
"anomalies": [
{
"hour": "2026-10-26T09",
"total": 16,
"errors": 16,
"error_rate": 1
},
{
"hour": "2026-10-29T15",
"total": 7,
"errors": 5,
"error_rate": 0.7143
}
],
"repeat_topics": [
{
"topic": "프린터",
"answers": 81,
"repeats": 8,
"repeat_rate": 0.0988
},
{
"topic": "비밀번호",
"answers": 139,
"repeats": 9,
"repeat_rate": 0.0647
},
{
"topic": "VPN",
"answers": 124,
"repeats": 8,
"repeat_rate": 0.0645
},
{
"topic": "접수 현황",
"answers": 96,
"repeats": 6,
"repeat_rate": 0.0625
},
{
"topic": "메일",
"answers": 90,
"repeats": 5,
"repeat_rate": 0.0556
},
{
"topic": "설치",
"answers": 61,
"repeats": 2,
"repeat_rate": 0.0328
}
]
}
✔ 첫 주 · 설치는 다시 묻지 않음 · 0.0s · 292 calls · $0.038550
→ request POST /webhook/my-log-report
{
"from": "2026-10-19",
"to": "2026-10-23"
}
← response HTTP 200
{
"total": 309,
"errors": 0,
"error_rate": 0,
"p50_ms": 1252,
"p95_ms": 2525,
"by_route": {
"자동 답변": 292,
"담당자 연결": 17
},
"by_day": {
"2026-10-19": {
"total": 73,
"errors": 0,
"error_rate": 0
},
"2026-10-20": {
"total": 57,
"errors": 0,
"error_rate": 0
},
"2026-10-21": {
"total": 60,
"errors": 0,
"error_rate": 0
},
"2026-10-22": {
"total": 55,
"errors": 0,
"error_rate": 0
},
"2026-10-23": {
"total": 64,
"errors": 0,
"error_rate": 0
}
},
"by_release": {
"1.0.0": {
"answers": 292,
"repeats": 16,
"repeat_rate": 0.0548
}
},
"steps": {
"faq_ms": {
"runs": 309,
"p50": 27,
"p95": 39
},
"answer_ms": {
"runs": 292,
"p50": 1200,
"p95": 2470
}
},
"cost_usd": 0.03855,
"cost_per_run": 0.000125,
"llm_calls": 292,
"failures": [],
"unanswered_topics": [
{
"topic": "와이파이",
"count": 17
}
],
"anomalies": [],
"repeat_topics": [
{
"topic": "프린터",
"answers": 45,
"repeats": 4,
"repeat_rate": 0.0889
},
{
"topic": "VPN",
"answers": 59,
"repeats": 4,
"repeat_rate": 0.0678
},
{
"topic": "비밀번호",
"answers": 69,
"repeats": 4,
"repeat_rate": 0.058
},
{
"topic": "접수 현황",
"answers": 40,
"repeats": 2,
"repeat_rate": 0.05
},
{
"topic": "메일",
"answers": 42,
"repeats": 2,
"repeat_rate": 0.0476
}
]
}
✔ 앞의 지표는 그대로 · 0.1s · 596 calls · $0.078360
→ request POST /webhook/my-log-report
{
"from": "2026-10-19",
"to": "2026-10-30"
}
← response HTTP 200
{
"total": 666,
"errors": 21,
"error_rate": 0.0315,
"p50_ms": 1205,
"p95_ms": 2537,
"by_route": {
"자동 답변": 591,
"담당자 연결": 34,
"오류": 21,
"잠시 후": 20
},
"by_day": {
"2026-10-19": {
"total": 73,
"errors": 0,
"error_rate": 0
},
"2026-10-20": {
"total": 57,
"errors": 0,
"error_rate": 0
},
"2026-10-21": {
"total": 60,
"errors": 0,
"error_rate": 0
},
"2026-10-22": {
"total": 55,
"errors": 0,
"error_rate": 0
},
"2026-10-23": {
"total": 64,
"errors": 0,
"error_rate": 0
},
"2026-10-26": {
"total": 70,
"errors": 16,
"error_rate": 0.2286
},
"2026-10-27": {
"total": 62,
"errors": 0,
"error_rate": 0
},
"2026-10-28": {
"total": 64,
"errors": 0,
"error_rate": 0
},
"2026-10-29": {
"total": 97,
"errors": 5,
"error_rate": 0.0515
},
"2026-10-30": {
"total": 64,
"errors": 0,
"error_rate": 0
}
},
"by_release": {
"1.0.0": {
"answers": 402,
"repeats": 19,
"repeat_rate": 0.0473
},
"1.1.0": {
"answers": 181,
"repeats": 14,
"repeat_rate": 0.0773
},
"1.2.0": {
"answers": 8,
"repeats": 5,
"repeat_rate": 0.625
}
},
"steps": {
"faq_ms": {
"runs": 646,
"p50": 27,
"p95": 39
},
"answer_ms": {
"runs": 596,
"p50": 1179,
"p95": 2509
}
},
"cost_usd": 0.07836,
"cost_per_run": 0.000118,
"llm_calls": 596,
"failures": [
{
"node": "Search FAQ",
"message": "timeout of 1000ms exceeded",
"count": 16
},
{
"node": "Answer",
"message": "429 Rate limit reached for requests",
"count": 5
}
],
"unanswered_topics": [
{
"topic": "와이파이",
"count": 34
}
],
"anomalies": [
{
"hour": "2026-10-26T09",
"total": 16,
"errors": 16,
"error_rate": 1
},
{
"hour": "2026-10-29T15",
"total": 7,
"errors": 5,
"error_rate": 0.7143
}
],
"repeat_topics": [
{
"topic": "프린터",
"answers": 81,
"repeats": 8,
"repeat_rate": 0.0988
},
{
"topic": "비밀번호",
"answers": 139,
"repeats": 9,
"repeat_rate": 0.0647
},
{
"topic": "VPN",
"answers": 124,
"repeats": 8,
"repeat_rate": 0.0645
},
{
"topic": "접수 현황",
"answers": 96,
"repeats": 6,
"repeat_rate": 0.0625
},
{
"topic": "메일",
"answers": 90,
"repeats": 5,
"repeat_rate": 0.0556
},
{
"topic": "설치",
"answers": 61,
"repeats": 2,
"repeat_rate": 0.0328
}
]
}
Passed 5/5
report: runs/lab02-challenge-20261031-075031.json
POST http://localhost:5678/webhook/my-log-report · 6 case(s) × 1
✔ 예제 1 · 가장 많은 실패 · 0.1s · 596 calls · $0.078360
✔ 예제 1 · 두 번째 실패 · 0.1s · 596 calls · $0.078360
✔ 예제 1 · 답하지 못한 주제 · 0.1s · 596 calls · $0.078360
✔ 예제 2 · 이상 시간대 1 · 0.1s · 596 calls · $0.078360
✔ 예제 2 · 이상 시간대 2 · 0.1s · 596 calls · $0.078360
✔ 예제 2 · 첫 주에는 없음 · 0.0s · 292 calls · $0.038550
Passed 6/6
report: runs/lab02-20261031-075031.json
```
**쉽게 말하면**
- 다시 묻는 **비율**은 프린터가 1위(81건 중 8건, 9.88%), **수**로는 비밀번호가 가장 많지만(9건) 비율은 6.47%로 2위. 다시 물은 주제는 6개, 마지막은 설치 3.28%. 와이파이는 답을 못 했으니(담당자 연결) 여기 없습니다.
- 첫 주에는 설치를 다시 묻지 않았습니다 (둘째 주에만 2건). `lab02` 6/6 그대로. 예상한 결과.
### 15 · Lab 02 과제 2 하기 전 → `lab02-challenge2` 0/3
실행한 명령:
```bash
uv run tools/flow.py test cases/lab02-challenge2.json -v
```
출력 (그대로):
```text
POST http://localhost:5678/webhook/my-log-summary · 3 case(s) × 1
✘ 요약 · 숫자는 통계에 있는 것만 · 0.0s · status 404 (expected 200); numbers_ok = null (expected true); top_topic = null (expected 와이파이); worst_hour = null (expected 2026-10-26T09)
→ request POST /webhook/my-log-summary
{
"from": "2026-10-19",
"to": "2026-10-30"
}
← response HTTP 404
{
"code": 404,
"message": "The requested webhook \"POST my-log-summary\" is not registered.",
"hint": "The workflow must be active for a production URL to run successfully. You can activate the workflow using the toggle in the top-right of the editor. Note that unlike test URL calls, production URL calls aren't shown on the canvas (only in the executions list)"
}
✘ 요약 · 주제와 시간대를 말함 · 0.0s · status 404 (expected 200); summary has none of ['와이파이']
→ request POST /webhook/my-log-summary
{
"from": "2026-10-19",
"to": "2026-10-30"
}
← response HTTP 404
{
"code": 404,
"message": "The requested webhook \"POST my-log-summary\" is not registered.",
"hint": "The workflow must be active for a production URL to run successfully. You can activate the workflow using the toggle in the top-right of the editor. Note that unlike test URL calls, production URL calls aren't shown on the canvas (only in the executions list)"
}
✘ 요약 · 날짜 · 0.0s · status 404 (expected 200); summary has none of ['10월 26일', '10-26', '26일']
→ request POST /webhook/my-log-summary
{
"from": "2026-10-19",
"to": "2026-10-30"
}
← response HTTP 404
{
"code": 404,
"message": "The requested webhook \"POST my-log-summary\" is not registered.",
"hint": "The workflow must be active for a production URL to run successfully. You can activate the workflow using the toggle in the top-right of the editor. Note that unlike test URL calls, production URL calls aren't shown on the canvas (only in the executions list)"
codex에 입력하는 프롬프트 (터미널 ①, 학생이 만들 파일 `my-work/log-summary.json` · 이 기록에서 push한 같은 역할의 정답 `answers/77-lab02-challenge2-summary.json`):
```text
my-work/log-summary.json 을 새로 만들어 줘. 웹훅 POST my-log-summary, 이름 "77 Log summary (my)".
Get report: 지표를 다시 계산하지 말고 HTTP POST http://localhost:5678/webhook/my-log-report 로 부른다 (본문 from · to · tag · source 그대로, timeout 30000).
Write summary(AI Agent + OpenAI gpt-4.1-mini, temperature 0): 통계 중 total · errors · error_rate · failures · unanswered_topics · anomalies 만 JSON 으로 주고, 한국어 3문장으로
가장 많은 답 못 한 주제와 수 · 가장 많은 실패(노드 · 메시지 · 수) · 가장 나쁜 시간대(10월 26일 09시처럼). 통계에 없는 숫자와 짐작한 원인은 쓰지 않는다.
Check numbers(Code): 요약 글의 숫자를 모두 뽑아, 통계의 값 · 비율의 ×100 · 키와 글자 속 숫자(날짜 · 시간)에 있는지 본다. 없는 숫자는 unknown_numbers 에, 하나도 없으면 numbers_ok true.
결과 {summary, numbers_ok, unknown_numbers, top_topic, worst_hour}. 기대 결과 cases/lab02-challenge2.json.
```
실행한 명령:
```bash
uv run tools/flow.py push answers/77-lab02-challenge2-summary.json
uv run tools/flow.py test cases/lab02-challenge2.json -v
uv run tools/flow.py call my-log-summary requests/week2.json
```
출력 (그대로):
```text
✔ pushed '77 Log summary (answer)' (id w9c86d93226f0b0f)
POST http://localhost:5678/webhook/my-log-summary
POST http://localhost:5678/webhook/my-log-summary · 3 case(s) × 1
✔ 요약 · 숫자는 통계에 있는 것만 · 3.4s
→ request POST /webhook/my-log-summary
{
"from": "2026-10-19",
"to": "2026-10-30"
}
← response HTTP 200
{
"summary": "가장 많은 미응답 주제는 와이파이로 34건입니다. 가장 흔한 장애는 Search FAQ 노드에서 발생한 \"timeout of 1000ms exceeded\" 메시지로 16건입니다. 가장 심각한 이상 현상은 10월 26일 09시에 발생했으며, 오류 16건과 총 16건의 요청이 있었습니다.",
"numbers_ok": true,
"unknown_numbers": [],
"top_topic": "와이파이",
"worst_hour": "2026-10-26T09"
}
✔ 요약 · 주제와 시간대를 말함 · 2.6s
→ request POST /webhook/my-log-summary
{
"from": "2026-10-19",
"to": "2026-10-30"
}
← response HTTP 200
{
"summary": "가장 많은 미응답 주제는 와이파이로 34건입니다. 가장 흔한 장애는 Search FAQ 노드에서 발생한 \"timeout of 1000ms exceeded\" 메시지로 16건입니다. 가장 심각한 이상 징후는 10월 26일 09시에 발생했으며, 오류 16건과 총 16건의 요청이 있었습니다.",
"numbers_ok": true,
"unknown_numbers": [],
"top_topic": "와이파이",
"worst_hour": "2026-10-26T09"
}
✔ 요약 · 날짜 · 1.7s
→ request POST /webhook/my-log-summary
{
"from": "2026-10-19",
"to": "2026-10-30"
}
← response HTTP 200
{
"summary": "가장 많은 미응답 주제는 와이파이로 34건입니다. 가장 흔한 장애는 Search FAQ 노드에서 발생한 \"timeout of 1000ms exceeded\" 메시지로 16건입니다. 가장 심각한 이상 징후는 10월 26일 09시에 발생했으며, 오류 16건과 총 16건이 보고되었습니다.",
"summary": "가장 많은 미응답 주제는 와이파이로 17건입니다. 가장 흔한 장애는 Search FAQ 노드에서 발생한 \"timeout of 1000ms exceeded\" 메시지로 16건입니다. 이상 징후가 가장 심한 시간대는 10월 26일 09시로, 총 16건 중 16건이 오류입니다.",
"numbers_ok": true,
"unknown_numbers": [],
"top_topic": "와이파이",
"worst_hour": "2026-10-26T09"
}
```
**쉽게 말하면**
- 요약(둘째 주): "가장 많은 미응답 주제는 와이파이로 17건입니다. 가장 흔한 장애는 Search FAQ 노드에서 발생한 \"timeout of 1000ms exceeded\" 메시지로 16건입니다. 이상 징후가 가장 심한 시간대는 10월 26일 09시로, 총 16건 중 16건이 오류입니다."
-`numbers_ok: true`, `unknown_numbers: []` — 17 · 1000 · 16 · 10 · 26 · 09가 모두 통계(값 · 메시지 · 시간 글자)에 있습니다. 요약은 1.7~3.4초 (LLM 한 번), 통계는 `my-log-report`를 다시 불러 받았습니다.
- LLM 글은 실행마다 조금 다를 수 있습니다. 숫자 확인이 그 차이를 잡습니다. 예상한 결과.
✔ 고친 뒤 · 답하지 못한 주제 없음 · 0.0s · 0 calls · $0.000000
→ request POST /webhook/my-log-report
{
"tag": "after",
"source": "live"
}
← response HTTP 200
{
"total": 0,
"errors": 0,
"error_rate": 0,
"p50_ms": 0,
"p95_ms": 0,
"by_route": {},
"by_day": {},
"by_release": {},
"steps": {
"faq_ms": {
"runs": 0,
"p50": 0,
"p95": 0
},
"answer_ms": {
"runs": 0,
"p50": 0,
"p95": 0
}
},
"cost_usd": 0,
"cost_per_run": 0,
"llm_calls": 0,
"failures": [],
"unanswered_topics": [],
"anomalies": [],
"repeat_topics": []
}
Passed 3/4
report: runs/lab03-20261031-075118.json
```
**쉽게 말하면**
- 제공 헬프데스크(FAQ timeout 1초, 와이파이 FAQ 없음)를 FAQ가 1.2초 느린 상태에서 10번 불렀습니다. `replay-before`는 '200이 오는가'만 보므로 10/10이지만, 기록을 보면 **10건 모두 오류**(`Search FAQ`, 1032~1035ms).
-`lab03` 3/4: 고치기 전 둘 ✔, '고친 뒤 · 오류 없음'은 고친 뒤 기록이 아직 없어 ✘ (`total = 0`). '답하지 못한 주제 없음'은 기록이 0건이라 빈 목록 — 우연히 ✔입니다. 예상한 결과.
> 11/02 고침: 이 기록(10/31) 뒤에 `cases/replay-after.json` · `replay-normal.json`의 `before` 맨 앞에 `logs-reset` (`{"tag": "after"}` · `{"tag": "normal"}`)을 더했습니다. 지금 돌리면 결과 줄 맨 위에 `✔ before: POST http://localhost:8800/logs-reset · … · {"cleared": 0}`이 한 줄 더 나옵니다 (다시 돌리면 `{"cleared": 10}`). 나머지 결과는 같습니다.
✔ 고친 뒤 · 답하지 못한 주제 없음 · 0.0s · 10 calls · $0.000000
→ request POST /webhook/my-log-report
{
"tag": "after",
"source": "live"
}
← response HTTP 200
{
"total": 10,
"errors": 0,
"error_rate": 0,
"p50_ms": 2342,
"p95_ms": 3560,
"by_route": {
"자동 답변": 10
},
"by_day": {
"2026-10-31": {
"total": 10,
"errors": 0,
"error_rate": 0
}
},
"by_release": {
"1.1.0": {
"answers": 10,
"repeats": 0,
"repeat_rate": 0
}
},
"steps": {
"faq_ms": {
"runs": 10,
"p50": 1238,
"p95": 1278
},
"answer_ms": {
"runs": 10,
"p50": 1103,
"p95": 2282
}
},
"cost_usd": 0,
"cost_per_run": 0,
"llm_calls": 10,
"failures": [],
"unanswered_topics": [],
"anomalies": [],
"repeat_topics": []
}
Passed 4/4
report: runs/lab03-20261031-075159.json
fault switch: all ok
live run logs: 20 (tag before 10 · tag after 10)
added FAQ: 1 (FAQ-007)
created tickets: 0
DLQ: 0 (parked 0)
alerts: 0
```
**쉽게 말하면**
- 워크플로우는 에이전트가(timeout 3초 · 재시도 2), 와이파이 FAQ는 내가 데이터에 더했습니다(`faq/add` → `FAQ-007`). 고치는 곳이 둘입니다.
- 같은 10개를 같은 느린 FAQ에서: 10건 모두 `자동 답변`, 와이파이 답에 `CORP-WIFI` · `사번`. 대신 한 건에 2.3~4.5초 — FAQ를 1.2초 기다리기 때문입니다.
-`lab03` 4/4 (고치기 전 10 오류 · 고친 뒤 0 오류 · 답 못 한 주제 없음). `ops`: 오늘 기록 before 10 · after 10, 더한 FAQ 1. 예상한 결과.
### 19 · Lab 03 예제 2 하기 전 → `lab03-slo` 0/4
실행한 명령:
```bash
uv run tools/flow.py test cases/lab03-slo.json -v
```
출력 (그대로):
```text
POST http://localhost:5678/webhook/my-log-report · 4 case(s) × 1
✘ 둘째 주 · SLO 못 지킴 · 0.1s · 304 calls · $0.039810 · slo.ok = null (expected false); unanswered_rate = null (expected 0.0476); slo has none of ['"error_rate"', '"unanswered_rate"']
→ request POST /webhook/my-log-report
{
"from": "2026-10-26",
"to": "2026-10-30"
}
← response HTTP 200
{
"total": 357,
"errors": 21,
"error_rate": 0.0588,
"p50_ms": 1171,
"p95_ms": 2598,
"by_route": {
"오류": 21,
"자동 답변": 299,
"담당자 연결": 17,
"잠시 후": 20
},
"by_day": {
"2026-10-26": {
"total": 70,
"errors": 16,
"error_rate": 0.2286
},
"2026-10-27": {
"total": 62,
"errors": 0,
"error_rate": 0
},
"2026-10-28": {
"total": 64,
"errors": 0,
"error_rate": 0
},
"2026-10-29": {
"total": 97,
"errors": 5,
"error_rate": 0.0515
},
"2026-10-30": {
"total": 64,
"errors": 0,
"error_rate": 0
}
},
"by_release": {
"1.0.0": {
"answers": 110,
"repeats": 3,
"repeat_rate": 0.0273
},
"1.1.0": {
"answers": 181,
"repeats": 14,
"repeat_rate": 0.0773
},
"1.2.0": {
"answers": 8,
"repeats": 5,
"repeat_rate": 0.625
}
},
"steps": {
"faq_ms": {
"runs": 337,
"p50": 28,
"p95": 40
},
"answer_ms": {
"runs": 304,
"p50": 1162,
"p95": 2532
}
},
"cost_usd": 0.03981,
"cost_per_run": 0.000112,
"llm_calls": 304,
"failures": [
{
"node": "Search FAQ",
"message": "timeout of 1000ms exceeded",
"count": 16
},
{
"node": "Answer",
"message": "429 Rate limit reached for requests",
"count": 5
}
],
"unanswered_topics": [
{
"topic": "와이파이",
"count": 17
}
],
"anomalies": [
{
"hour": "2026-10-26T09",
"total": 16,
"errors": 16,
"error_rate": 1
},
{
"hour": "2026-10-29T15",
"total": 7,
"errors": 5,
"error_rate": 0.7143
}
],
"repeat_topics": [
{
"topic": "프린터",
"answers": 36,
"repeats": 4,
"repeat_rate": 0.1111
},
{
"topic": "설치",
"answers": 24,
"repeats": 2,
"repeat_rate": 0.0833
},
{
"topic": "비밀번호",
"answers": 70,
"repeats": 5,
"repeat_rate": 0.0714
},
{
"topic": "접수 현황",
"answers": 56,
"repeats": 4,
"repeat_rate": 0.0714
},
{
"topic": "메일",
"answers": 48,
"repeats": 3,
"repeat_rate": 0.0625
},
{
"topic": "VPN",
"answers": 65,
"repeats": 4,
"repeat_rate": 0.0615
}
]
}
✘ 첫 주 · 답 못 함만 · 0.1s · 292 calls · $0.038550 · slo.ok = null (expected false); slo.breaches = null (expected ["unanswered_rate"])
→ request POST /webhook/my-log-report
{
"from": "2026-10-19",
"to": "2026-10-23"
}
← response HTTP 200
{
"total": 309,
"errors": 0,
"error_rate": 0,
"p50_ms": 1252,
"p95_ms": 2525,
"by_route": {
"자동 답변": 292,
"담당자 연결": 17
},
"by_day": {
"2026-10-19": {
"total": 73,
"errors": 0,
"error_rate": 0
},
"2026-10-20": {
"total": 57,
"errors": 0,
"error_rate": 0
},
"2026-10-21": {
"total": 60,
"errors": 0,
"error_rate": 0
},
"2026-10-22": {
"total": 55,
"errors": 0,
"error_rate": 0
},
"2026-10-23": {
"total": 64,
"errors": 0,
"error_rate": 0
}
},
"by_release": {
"1.0.0": {
"answers": 292,
"repeats": 16,
"repeat_rate": 0.0548
}
},
"steps": {
"faq_ms": {
"runs": 309,
"p50": 27,
"p95": 39
},
"answer_ms": {
"runs": 292,
"p50": 1200,
"p95": 2470
}
},
"cost_usd": 0.03855,
"cost_per_run": 0.000125,
"llm_calls": 292,
"failures": [],
"unanswered_topics": [
{
"topic": "와이파이",
"count": 17
}
],
"anomalies": [],
"repeat_topics": [
{
"topic": "프린터",
"answers": 45,
"repeats": 4,
"repeat_rate": 0.0889
},
{
"topic": "VPN",
"answers": 59,
"repeats": 4,
"repeat_rate": 0.0678
},
{
"topic": "비밀번호",
"answers": 69,
"repeats": 4,
"repeat_rate": 0.058
},
{
"topic": "접수 현황",
"answers": 40,
"repeats": 2,
"repeat_rate": 0.05
},
{
"topic": "메일",
"answers": 42,
"repeats": 2,
"repeat_rate": 0.0476
}
]
}
✘ 기준을 바꾸면 · 첫 주 · 0.1s · 292 calls · $0.038550 · slo.ok = null (expected true)
→ request POST /webhook/my-log-report
{
"from": "2026-10-19",
"to": "2026-10-23",
"slo": {
"unanswered_rate": 0.06
}
}
← response HTTP 200
{
"total": 309,
"errors": 0,
"error_rate": 0,
"p50_ms": 1252,
"p95_ms": 2525,
"by_route": {
"자동 답변": 292,
"담당자 연결": 17
},
"by_day": {
"2026-10-19": {
"total": 73,
"errors": 0,
"error_rate": 0
},
"2026-10-20": {
"total": 57,
"errors": 0,
"error_rate": 0
},
"2026-10-21": {
"total": 60,
"errors": 0,
"error_rate": 0
},
"2026-10-22": {
"total": 55,
"errors": 0,
"error_rate": 0
},
"2026-10-23": {
"total": 64,
"errors": 0,
"error_rate": 0
}
},
"by_release": {
"1.0.0": {
"answers": 292,
"repeats": 16,
"repeat_rate": 0.0548
}
},
"steps": {
"faq_ms": {
"runs": 309,
"p50": 27,
"p95": 39
},
"answer_ms": {
"runs": 292,
"p50": 1200,
"p95": 2470
}
},
"cost_usd": 0.03855,
"cost_per_run": 0.000125,
"llm_calls": 292,
"failures": [],
"unanswered_topics": [
{
"topic": "와이파이",
"count": 17
}
],
"anomalies": [],
"repeat_topics": [
{
"topic": "프린터",
"answers": 45,
"repeats": 4,
"repeat_rate": 0.0889
},
{
"topic": "VPN",
"answers": 59,
"repeats": 4,
"repeat_rate": 0.0678
},
{
"topic": "비밀번호",
"answers": 69,
"repeats": 4,
"repeat_rate": 0.058
},
{
"topic": "접수 현황",
"answers": 40,
"repeats": 2,
"repeat_rate": 0.05
},
{
"topic": "메일",
"answers": 42,
"repeats": 2,
"repeat_rate": 0.0476
}
]
}
✘ 고친 뒤 · 오류 · 답 못 함 기준은 지킴 · 0.1s · 10 calls · $0.000000 · unanswered_rate = null (expected 0)
→ request POST /webhook/my-log-report
{
"tag": "after",
"source": "live"
}
← response HTTP 200
{
"total": 10,
"errors": 0,
"error_rate": 0,
"p50_ms": 2342,
"p95_ms": 3560,
"by_route": {
"자동 답변": 10
},
"by_day": {
"2026-10-31": {
"total": 10,
"errors": 0,
"error_rate": 0
}
},
"by_release": {
"1.1.0": {
"answers": 10,
"repeats": 0,
"repeat_rate": 0
}
},
"steps": {
"faq_ms": {
"runs": 10,
"p50": 1238,
"p95": 1278
},
"answer_ms": {
"runs": 10,
"p50": 1103,
"p95": 2282
}
},
"cost_usd": 0,
"cost_per_run": 0,
"llm_calls": 10,
"failures": [],
"unanswered_topics": [],
"anomalies": [],
"repeat_topics": []
}
Passed 0/4
report: runs/lab03-slo-20261031-075159.json
```
**쉽게 말하면**
- 보고서에 `unanswered_rate` · `slo`가 없어 모두 `null`. 예상한 결과.
### 20 · Lab 03 예제 2 · SLO로 판정 → 4/4
codex에 입력하는 프롬프트 (터미널 ①, 학생이 만들 파일 `my-work/log-report.json` · 이 기록에서 push한 같은 역할의 정답 `reference/lab03-example2-slo.json`):
```text
my-work/log-report.json 의 Compute metrics 에 unanswered_rate 와 slo 를 더해 줘.
unanswered_rate = "담당자 연결" 수 / total (소수 4자리).
기준 limits 는 기본 error_rate 0.01 · p95_ms 3000 · unanswered_rate 0.02, 웹훅 본문에 slo 가 있으면 그 값으로 덮어쓴다 (본문은 $('Report webhook').first().json.body).
지표가 기준보다 크면 그 이름을 breaches 에 넣고, slo = {ok: breaches 가 비었으면 true, breaches, limits}.
앞의 지표는 그대로. 기대 결과 cases/lab03-slo.json.
```
실행한 명령:
```bash
uv run tools/flow.py push reference/lab03-example2-slo.json
uv run tools/flow.py test cases/lab03-slo.json -v
uv run tools/flow.py call my-log-report '{"tag": "after", "source": "live"}'
uv run tools/flow.py test cases/lab02-challenge.json
```
출력 (그대로):
```text
! unpublished '77 Log report + repeat topics (answer)' (wf3d06e3d30eeee6): it used the same webhook path
✔ pushed '77 Log report + SLO (reference)' (id wfed832ca6c81732)
POST http://localhost:5678/webhook/my-log-report
POST http://localhost:5678/webhook/my-log-report · 4 case(s) × 1
✔ 둘째 주 · SLO 못 지킴 · 0.9s · 304 calls · $0.039810
→ request POST /webhook/my-log-report
{
"from": "2026-10-26",
"to": "2026-10-30"
}
← response HTTP 200
{
"total": 357,
"errors": 21,
"error_rate": 0.0588,
"p50_ms": 1171,
"p95_ms": 2598,
"by_route": {
"오류": 21,
"자동 답변": 299,
"담당자 연결": 17,
"잠시 후": 20
},
"by_day": {
"2026-10-26": {
"total": 70,
"errors": 16,
"error_rate": 0.2286
},
"2026-10-27": {
"total": 62,
"errors": 0,
"error_rate": 0
},
"2026-10-28": {
"total": 64,
"errors": 0,
"error_rate": 0
},
"2026-10-29": {
"total": 97,
"errors": 5,
"error_rate": 0.0515
},
"2026-10-30": {
"total": 64,
"errors": 0,
"error_rate": 0
}
},
"by_release": {
"1.0.0": {
"answers": 110,
"repeats": 3,
"repeat_rate": 0.0273
},
"1.1.0": {
"answers": 181,
"repeats": 14,
"repeat_rate": 0.0773
},
"1.2.0": {
"answers": 8,
"repeats": 5,
"repeat_rate": 0.625
}
},
"steps": {
"faq_ms": {
"runs": 337,
"p50": 28,
"p95": 40
},
"answer_ms": {
"runs": 304,
"p50": 1162,
"p95": 2532
}
},
"cost_usd": 0.03981,
"cost_per_run": 0.000112,
"llm_calls": 304,
"failures": [
{
"node": "Search FAQ",
"message": "timeout of 1000ms exceeded",
"count": 16
},
{
"node": "Answer",
"message": "429 Rate limit reached for requests",
"count": 5
}
],
"unanswered_topics": [
{
"topic": "와이파이",
"count": 17
}
],
"anomalies": [
{
"hour": "2026-10-26T09",
"total": 16,
"errors": 16,
"error_rate": 1
},
{
"hour": "2026-10-29T15",
"total": 7,
"errors": 5,
"error_rate": 0.7143
}
],
"repeat_topics": [
{
"topic": "프린터",
"answers": 36,
"repeats": 4,
"repeat_rate": 0.1111
},
{
"topic": "설치",
"answers": 24,
"repeats": 2,
"repeat_rate": 0.0833
},
{
"topic": "비밀번호",
"answers": 70,
"repeats": 5,
"repeat_rate": 0.0714
},
{
"topic": "접수 현황",
"answers": 56,
"repeats": 4,
"repeat_rate": 0.0714
},
{
"topic": "메일",
"answers": 48,
"repeats": 3,
"repeat_rate": 0.0625
},
{
"topic": "VPN",
"answers": 65,
"repeats": 4,
"repeat_rate": 0.0615
}
],
"unanswered_rate": 0.0476,
"slo": {
"ok": false,
"breaches": [
"error_rate",
"unanswered_rate"
],
"limits": {
"error_rate": 0.01,
"p95_ms": 3000,
"unanswered_rate": 0.02
}
}
}
✔ 첫 주 · 답 못 함만 · 0.1s · 292 calls · $0.038550
→ request POST /webhook/my-log-report
{
"from": "2026-10-19",
"to": "2026-10-23"
}
← response HTTP 200
{
"total": 309,
"errors": 0,
"error_rate": 0,
"p50_ms": 1252,
"p95_ms": 2525,
"by_route": {
"자동 답변": 292,
"담당자 연결": 17
},
"by_day": {
"2026-10-19": {
"total": 73,
"errors": 0,
"error_rate": 0
},
"2026-10-20": {
"total": 57,
"errors": 0,
"error_rate": 0
},
"2026-10-21": {
"total": 60,
"errors": 0,
"error_rate": 0
},
"2026-10-22": {
"total": 55,
"errors": 0,
"error_rate": 0
},
"2026-10-23": {
"total": 64,
"errors": 0,
"error_rate": 0
}
},
"by_release": {
"1.0.0": {
"answers": 292,
"repeats": 16,
"repeat_rate": 0.0548
}
},
"steps": {
"faq_ms": {
"runs": 309,
"p50": 27,
"p95": 39
},
"answer_ms": {
"runs": 292,
"p50": 1200,
"p95": 2470
}
},
"cost_usd": 0.03855,
"cost_per_run": 0.000125,
"llm_calls": 292,
"failures": [],
"unanswered_topics": [
{
"topic": "와이파이",
"count": 17
}
],
"anomalies": [],
"repeat_topics": [
{
"topic": "프린터",
"answers": 45,
"repeats": 4,
"repeat_rate": 0.0889
},
{
"topic": "VPN",
"answers": 59,
"repeats": 4,
"repeat_rate": 0.0678
},
{
"topic": "비밀번호",
"answers": 69,
"repeats": 4,
"repeat_rate": 0.058
},
{
"topic": "접수 현황",
"answers": 40,
"repeats": 2,
"repeat_rate": 0.05
},
{
"topic": "메일",
"answers": 42,
"repeats": 2,
"repeat_rate": 0.0476
}
],
"unanswered_rate": 0.055,
"slo": {
"ok": false,
"breaches": [
"unanswered_rate"
],
"limits": {
"error_rate": 0.01,
"p95_ms": 3000,
"unanswered_rate": 0.02
}
}
}
✔ 기준을 바꾸면 · 첫 주 · 0.1s · 292 calls · $0.038550
→ request POST /webhook/my-log-report
{
"from": "2026-10-19",
"to": "2026-10-23",
"slo": {
"unanswered_rate": 0.06
}
}
← response HTTP 200
{
"total": 309,
"errors": 0,
"error_rate": 0,
"p50_ms": 1252,
"p95_ms": 2525,
"by_route": {
"자동 답변": 292,
"담당자 연결": 17
},
"by_day": {
"2026-10-19": {
"total": 73,
"errors": 0,
"error_rate": 0
},
"2026-10-20": {
"total": 57,
"errors": 0,
"error_rate": 0
},
"2026-10-21": {
"total": 60,
"errors": 0,
"error_rate": 0
},
"2026-10-22": {
"total": 55,
"errors": 0,
"error_rate": 0
},
"2026-10-23": {
"total": 64,
"errors": 0,
"error_rate": 0
}
},
"by_release": {
"1.0.0": {
"answers": 292,
"repeats": 16,
"repeat_rate": 0.0548
}
},
"steps": {
"faq_ms": {
"runs": 309,
"p50": 27,
"p95": 39
},
"answer_ms": {
"runs": 292,
"p50": 1200,
"p95": 2470
}
},
"cost_usd": 0.03855,
"cost_per_run": 0.000125,
"llm_calls": 292,
"failures": [],
"unanswered_topics": [
{
"topic": "와이파이",
"count": 17
}
],
"anomalies": [],
"repeat_topics": [
{
"topic": "프린터",
"answers": 45,
"repeats": 4,
"repeat_rate": 0.0889
},
{
"topic": "VPN",
"answers": 59,
"repeats": 4,
"repeat_rate": 0.0678
},
{
"topic": "비밀번호",
"answers": 69,
"repeats": 4,
"repeat_rate": 0.058
},
{
"topic": "접수 현황",
"answers": 40,
"repeats": 2,
"repeat_rate": 0.05
},
{
"topic": "메일",
"answers": 42,
"repeats": 2,
"repeat_rate": 0.0476
}
],
"unanswered_rate": 0.055,
"slo": {
"ok": true,
"breaches": [],
"limits": {
"error_rate": 0.01,
"p95_ms": 3000,
"unanswered_rate": 0.06
}
}
}
✔ 고친 뒤 · 오류 · 답 못 함 기준은 지킴 · 0.2s · 10 calls · $0.000000
→ request POST /webhook/my-log-report
{
"tag": "after",
"source": "live"
}
← response HTTP 200
{
"total": 10,
"errors": 0,
"error_rate": 0,
"p50_ms": 2342,
"p95_ms": 3560,
"by_route": {
"자동 답변": 10
},
"by_day": {
"2026-10-31": {
"total": 10,
"errors": 0,
"error_rate": 0
}
},
"by_release": {
"1.1.0": {
"answers": 10,
"repeats": 0,
"repeat_rate": 0
}
},
"steps": {
"faq_ms": {
"runs": 10,
"p50": 1238,
"p95": 1278
},
"answer_ms": {
"runs": 10,
"p50": 1103,
"p95": 2282
}
},
"cost_usd": 0,
"cost_per_run": 0,
"llm_calls": 10,
"failures": [],
"unanswered_topics": [],
"anomalies": [],
"repeat_topics": [],
"unanswered_rate": 0,
"slo": {
"ok": false,
"breaches": [
"p95_ms"
],
"limits": {
"error_rate": 0.01,
"p95_ms": 3000,
"unanswered_rate": 0.02
}
}
}
Passed 4/4
report: runs/lab03-slo-20261031-075213.json
HTTP 200 · 0.0s
{
"total": 10,
"errors": 0,
"error_rate": 0,
"p50_ms": 2342,
"p95_ms": 3560,
"by_route": {
"자동 답변": 10
},
"by_day": {
"2026-10-31": {
"total": 10,
"errors": 0,
"error_rate": 0
}
},
"by_release": {
"1.1.0": {
"answers": 10,
"repeats": 0,
"repeat_rate": 0
}
},
"steps": {
"faq_ms": {
"runs": 10,
"p50": 1238,
"p95": 1278
},
"answer_ms": {
"runs": 10,
"p50": 1103,
"p95": 2282
}
},
"cost_usd": 0,
"cost_per_run": 0,
"llm_calls": 10,
"failures": [],
"unanswered_topics": [],
"anomalies": [],
"repeat_topics": [],
"unanswered_rate": 0,
"slo": {
"ok": false,
"breaches": [
"p95_ms"
],
"limits": {
"error_rate": 0.01,
"p95_ms": 3000,
"unanswered_rate": 0.02
}
}
}
POST http://localhost:5678/webhook/my-log-report · 5 case(s) × 1
✔ 두 주 · 다시 묻는 비율이 가장 높은 주제 · 0.1s · 596 calls · $0.078360
✔ 두 주 · 수로는 비밀번호가 가장 많지만 비율은 2위 · 0.1s · 596 calls · $0.078360
✔ 두 주 · 다시 물은 주제는 6개 · 0.1s · 596 calls · $0.078360
✔ 첫 주 · 설치는 다시 묻지 않음 · 0.1s · 292 calls · $0.038550
✔ 앞의 지표는 그대로 · 0.1s · 596 calls · $0.078360
Passed 5/5
report: runs/lab02-challenge-20261031-075213.json
```
**쉽게 말하면**
- 둘째 주: 오류율 0.0588 > 0.01, 답 못 함 0.0476 > 0.02 → `breaches: [error_rate, unanswered_rate]`, p95 2598은 3000 안. 첫 주: 답 못 함 0.055만 어김. 기준을 0.06으로 바꾸면 첫 주는 지킴.
- 고친 뒤 기록(`tag after`): 오류 0 · 답 못 함 0이지만 **p95 3560ms > 3000** → `breaches: [p95_ms]`. 오류를 없앤 대가로 느려졌습니다 (FAQ를 1.2초 기다림, 단계 FAQ p50 1238ms).
> 11/02 고침: 이 기록(10/31) 뒤에 `cases/replay-after.json` · `replay-normal.json`의 `before` 맨 앞에 `logs-reset` (`{"tag": "after"}` · `{"tag": "normal"}`)을 더했습니다. 지금 돌리면 결과 줄 맨 위에 `✔ before: POST http://localhost:8800/logs-reset · … · {"cleared": 0}`이 한 줄 더 나옵니다 (다시 돌리면 `{"cleared": 10}`). 나머지 결과는 같습니다.
- timeout을 늘린 것은 '느린 FAQ를 견디는' 고침이지 '빠르게' 하는 고침이 아닙니다. FAQ가 느린 동안 사용자는 그만큼 기다립니다. `ops`: before 10 · after 10 · normal 10. 예상한 결과.
### 22 · Lab 03 과제 1 하기 전 → `lab03-challenge` 0/7
실행한 명령:
```bash
uv run tools/flow.py test cases/lab03-challenge.json -v
```
출력 (그대로):
```text
POST http://localhost:5678/webhook/my-weekly · 7 case(s) × 1
✘ 주간 보고 · 숫자 · 0.0s · status 404 (expected 200); total = null (expected 357); error_rate = null (expected 0.0588); slo_ok = null (expected false); numbers_ok = null (expected true)
→ request POST /webhook/my-weekly
{
"from": "2026-10-26",
"to": "2026-10-30",
"prev_from": "2026-10-19",
"prev_to": "2026-10-23"
}
← response HTTP 404
{
"code": 404,
"message": "The requested webhook \"POST my-weekly\" is not registered.",
"hint": "The workflow must be active for a production URL to run successfully. You can activate the workflow using the toggle in the top-right of the editor. Note that unlike test URL calls, production URL calls aren't shown on the canvas (only in the executions list)"
}
✘ 주간 보고 · 절 · 0.0s · status 404 (expected 200); markdown has none of ['## 숫자']
→ request POST /webhook/my-weekly
{
"from": "2026-10-26",
"to": "2026-10-30",
"prev_from": "2026-10-19",
"prev_to": "2026-10-23"
}
← response HTTP 404
{
"code": 404,
"message": "The requested webhook \"POST my-weekly\" is not registered.",
"hint": "The workflow must be active for a production URL to run successfully. You can activate the workflow using the toggle in the top-right of the editor. Note that unlike test URL calls, production URL calls aren't shown on the canvas (only in the executions list)"
}
✘ 주간 보고 · 문제 절 · 0.0s · status 404 (expected 200); markdown has none of ['## 문제']
→ request POST /webhook/my-weekly
{
"from": "2026-10-26",
"to": "2026-10-30",
"prev_from": "2026-10-19",
"prev_to": "2026-10-23"
}
← response HTTP 404
{
"code": 404,
"message": "The requested webhook \"POST my-weekly\" is not registered.",
"hint": "The workflow must be active for a production URL to run successfully. You can activate the workflow using the toggle in the top-right of the editor. Note that unlike test URL calls, production URL calls aren't shown on the canvas (only in the executions list)"
}
✘ 주간 보고 · 다음 할 일 · 0.0s · status 404 (expected 200); markdown has none of ['## 다음 할 일']
→ request POST /webhook/my-weekly
{
"from": "2026-10-26",
"to": "2026-10-30",
"prev_from": "2026-10-19",
"prev_to": "2026-10-23"
}
← response HTTP 404
{
"code": 404,
"message": "The requested webhook \"POST my-weekly\" is not registered.",
"hint": "The workflow must be active for a production URL to run successfully. You can activate the workflow using the toggle in the top-right of the editor. Note that unlike test URL calls, production URL calls aren't shown on the canvas (only in the executions list)"
}
✘ 주간 보고 · 비교 숫자 · 0.0s · status 404 (expected 200); markdown has none of ['| 요청 | 309 | 357 |']
→ request POST /webhook/my-weekly
{
"from": "2026-10-26",
"to": "2026-10-30",
"prev_from": "2026-10-19",
"prev_to": "2026-10-23"
}
← response HTTP 404
{
"code": 404,
"message": "The requested webhook \"POST my-weekly\" is not registered.",
"hint": "The workflow must be active for a production URL to run successfully. You can activate the workflow using the toggle in the top-right of the editor. Note that unlike test URL calls, production URL calls aren't shown on the canvas (only in the executions list)"
}
✘ 주간 보고 · 이상 시간대 · 0.0s · status 404 (expected 200); markdown has none of ['2026-10-26 09시']
→ request POST /webhook/my-weekly
{
"from": "2026-10-26",
"to": "2026-10-30",
"prev_from": "2026-10-19",
"prev_to": "2026-10-23"
}
← response HTTP 404
{
"code": 404,
"message": "The requested webhook \"POST my-weekly\" is not registered.",
"hint": "The workflow must be active for a production URL to run successfully. You can activate the workflow using the toggle in the top-right of the editor. Note that unlike test URL calls, production URL calls aren't shown on the canvas (only in the executions list)"
}
✘ 주간 보고 · 와이파이 · 0.0s · status 404 (expected 200); markdown has none of ["FAQ에 '와이파이' 항목 추가"]
→ request POST /webhook/my-weekly
{
"from": "2026-10-26",
"to": "2026-10-30",
"prev_from": "2026-10-19",
"prev_to": "2026-10-23"
}
← response HTTP 404
{
"code": 404,
"message": "The requested webhook \"POST my-weekly\" is not registered.",
"hint": "The workflow must be active for a production URL to run successfully. You can activate the workflow using the toggle in the top-right of the editor. Note that unlike test URL calls, production URL calls aren't shown on the canvas (only in the executions list)"
}
Passed 0/7
report: runs/lab03-challenge-20261031-075226.json
```
**쉽게 말하면**
-`my-weekly`가 아직 없어 404. 예상한 결과.
### 23 · Lab 03 과제 1 · 주간 보고 → 7/7
codex에 입력하는 프롬프트 (터미널 ①, 학생이 만들 파일 `my-work/weekly.json` · 이 기록에서 push한 같은 역할의 정답 `answers/77-lab03-challenge-weekly.json`):
```text
my-work/weekly.json 을 새로 만들어 줘. 웹훅 POST my-weekly, 본문 from · to · prev_from · prev_to, 이름 "77 Weekly report (my)".
This week · Last week: my-log-report 를 두 번 부른다 (이번 주 from · to, 지난주 prev_from · prev_to). Summary: my-log-summary 를 이번 주로 부른다 (timeout 60000).
Write report(Code)가 마크다운을 만든다. ## 숫자: | 지표 | 지난주 | 이번 주 | 표 (요청 · 오류율 · p95 · 답 못 함 · SLO), 비율은 0.0588 을 5.88%처럼.
## 문제: 실패 · 답하지 못한 질문 · 이상 시간대("2026-10-26 09시"). ## 요약: LLM 요약과 숫자 확인 결과.
## 다음 할 일: LLM 이 아니라 규칙으로 — 답 못 한 주제가 있으면 "FAQ에 '<주제>' 항목 추가", Search FAQ 실패가 있으면 timeout 점검, 429 가 있으면 사용량 한도 점검.
결과 {markdown, total, error_rate, slo_ok, numbers_ok}. 기대 결과 cases/lab03-challenge.json.
```
실행한 명령:
```bash
uv run tools/flow.py push answers/77-lab03-challenge-weekly.json
uv run tools/flow.py test cases/lab03-challenge.json -v
uv run tools/flow.py call my-weekly requests/weekly.json
```
출력 (그대로):
```text
✔ pushed '77 Weekly report (answer)' (id w269ccf31103289f)
POST http://localhost:5678/webhook/my-weekly
POST http://localhost:5678/webhook/my-weekly · 7 case(s) × 1
✔ 주간 보고 · 숫자 · 3.6s
→ request POST /webhook/my-weekly
{
"from": "2026-10-26",
"to": "2026-10-30",
"prev_from": "2026-10-19",
"prev_to": "2026-10-23"
}
← response HTTP 200
{
"markdown": "# IT 헬프데스크 주간 운영 보고 (2026-10-26 ~ 2026-10-30)\n\n## 숫자\n\n| 지표 | 지난주 | 이번 주 |\n| --- | --- | --- |\n| 요청 | 309 | 357 |\n| 오류율 | 0% | 5.88% |\n| p95 | 2525ms | 2598ms |\n| 답 못 함 | 5.5% | 4.76% |\n| SLO | 못 지킴 unanswered_rate | 못 지킴 error_rate, unanswered_rate |\n\n## 문제\n\n- 실패 16건 · Search FAQ · timeout of 1000ms exceeded\n- 실패 5건 · Answer · 429 Rate limit reached for requests\n- 답하지 못한 질문 17건 · 와이파이\n- 이상 시간대 2026-10-26 09시 · 16/16 실패\n- 이상 시간대 2026-10-29 15시 · 5/7 실패\n\n## 요약 (LLM, 숫자 확인 통과)\n\n가장 많은 미응답 주제는 와이파이로 17건입니다. 가장 흔한 장애는 Search FAQ 노드에서 발생한 \"timeout of 1000ms exceeded\" 메시지로 16건입니다. 이상 징후가 가장 심한 시간대는 10월 26일 09시로 오류 16건, 전체 16건입니다.\n\n## 다음 할 일\n\n- FAQ에 '와이파이' 항목 추가\n- FAQ 검색 timeout · 재시도 설정 점검 (72일차)\n- LLM 사용량 한도 · 대체 경로 점검 (75 · 72일차)",
"total": 357,
"error_rate": 0.0588,
"slo_ok": false,
"numbers_ok": true
}
✔ 주간 보고 · 절 · 1.9s
→ request POST /webhook/my-weekly
{
"from": "2026-10-26",
"to": "2026-10-30",
"prev_from": "2026-10-19",
"prev_to": "2026-10-23"
}
← response HTTP 200
{
"markdown": "# IT 헬프데스크 주간 운영 보고 (2026-10-26 ~ 2026-10-30)\n\n## 숫자\n\n| 지표 | 지난주 | 이번 주 |\n| --- | --- | --- |\n| 요청 | 309 | 357 |\n| 오류율 | 0% | 5.88% |\n| p95 | 2525ms | 2598ms |\n| 답 못 함 | 5.5% | 4.76% |\n| SLO | 못 지킴 unanswered_rate | 못 지킴 error_rate, unanswered_rate |\n\n## 문제\n\n- 실패 16건 · Search FAQ · timeout of 1000ms exceeded\n- 실패 5건 · Answer · 429 Rate limit reached for requests\n- 답하지 못한 질문 17건 · 와이파이\n- 이상 시간대 2026-10-26 09시 · 16/16 실패\n- 이상 시간대 2026-10-29 15시 · 5/7 실패\n\n## 요약 (LLM, 숫자 확인 통과)\n\n가장 많은 미응답 주제는 와이파이로 17건입니다. 가장 흔한 장애는 Search FAQ 노드에서 발생한 \"timeout of 1000ms exceeded\" 메시지로 16건입니다. 이상 징후가 가장 심한 시간대는 10월 26일 09시로, 총 16건 중 16건이 오류입니다.\n\n## 다음 할 일\n\n- FAQ에 '와이파이' 항목 추가\n- FAQ 검색 timeout · 재시도 설정 점검 (72일차)\n- LLM 사용량 한도 · 대체 경로 점검 (75 · 72일차)",
"total": 357,
"error_rate": 0.0588,
"slo_ok": false,
"numbers_ok": true
}
✔ 주간 보고 · 문제 절 · 2.4s
→ request POST /webhook/my-weekly
{
"from": "2026-10-26",
"to": "2026-10-30",
"prev_from": "2026-10-19",
"prev_to": "2026-10-23"
}
← response HTTP 200
{
"markdown": "# IT 헬프데스크 주간 운영 보고 (2026-10-26 ~ 2026-10-30)\n\n## 숫자\n\n| 지표 | 지난주 | 이번 주 |\n| --- | --- | --- |\n| 요청 | 309 | 357 |\n| 오류율 | 0% | 5.88% |\n| p95 | 2525ms | 2598ms |\n| 답 못 함 | 5.5% | 4.76% |\n| SLO | 못 지킴 unanswered_rate | 못 지킴 error_rate, unanswered_rate |\n\n## 문제\n\n- 실패 16건 · Search FAQ · timeout of 1000ms exceeded\n- 실패 5건 · Answer · 429 Rate limit reached for requests\n- 답하지 못한 질문 17건 · 와이파이\n- 이상 시간대 2026-10-26 09시 · 16/16 실패\n- 이상 시간대 2026-10-29 15시 · 5/7 실패\n\n## 요약 (LLM, 숫자 확인 통과)\n\n가장 많은 미응답 주제는 와이파이로 17건입니다. 가장 흔한 장애는 Search FAQ 노드에서 발생한 \"timeout of 1000ms exceeded\" 메시지로 16건입니다. 이상 징후가 가장 심한 시간대는 10월 26일 09시로, 총 16건 중 16건이 오류입니다.\n\n## 다음 할 일\n\n- FAQ에 '와이파이' 항목 추가\n- FAQ 검색 timeout · 재시도 설정 점검 (72일차)\n- LLM 사용량 한도 · 대체 경로 점검 (75 · 72일차)",
"total": 357,
"error_rate": 0.0588,
"slo_ok": false,
"numbers_ok": true
}
✔ 주간 보고 · 다음 할 일 · 1.7s
→ request POST /webhook/my-weekly
{
"from": "2026-10-26",
"to": "2026-10-30",
"prev_from": "2026-10-19",
"prev_to": "2026-10-23"
}
← response HTTP 200
{
"markdown": "# IT 헬프데스크 주간 운영 보고 (2026-10-26 ~ 2026-10-30)\n\n## 숫자\n\n| 지표 | 지난주 | 이번 주 |\n| --- | --- | --- |\n| 요청 | 309 | 357 |\n| 오류율 | 0% | 5.88% |\n| p95 | 2525ms | 2598ms |\n| 답 못 함 | 5.5% | 4.76% |\n| SLO | 못 지킴 unanswered_rate | 못 지킴 error_rate, unanswered_rate |\n\n## 문제\n\n- 실패 16건 · Search FAQ · timeout of 1000ms exceeded\n- 실패 5건 · Answer · 429 Rate limit reached for requests\n- 답하지 못한 질문 17건 · 와이파이\n- 이상 시간대 2026-10-26 09시 · 16/16 실패\n- 이상 시간대 2026-10-29 15시 · 5/7 실패\n\n## 요약 (LLM, 숫자 확인 통과)\n\n가장 많은 미응답 주제는 와이파이로 17건입니다. 가장 흔한 장애는 Search FAQ 노드에서 발생한 \"timeout of 1000ms exceeded\" 메시지로 16건입니다. 가장 심각한 이상 징후는 10월 26일 09시에 발생했으며, 오류 16건과 총 16건의 요청이 있었습니다.\n\n## 다음 할 일\n\n- FAQ에 '와이파이' 항목 추가\n- FAQ 검색 timeout · 재시도 설정 점검 (72일차)\n- LLM 사용량 한도 · 대체 경로 점검 (75 · 72일차)",
"total": 357,
"error_rate": 0.0588,
"slo_ok": false,
"numbers_ok": true
}
✔ 주간 보고 · 비교 숫자 · 2.0s
→ request POST /webhook/my-weekly
{
"from": "2026-10-26",
"to": "2026-10-30",
"prev_from": "2026-10-19",
"prev_to": "2026-10-23"
}
← response HTTP 200
{
"markdown": "# IT 헬프데스크 주간 운영 보고 (2026-10-26 ~ 2026-10-30)\n\n## 숫자\n\n| 지표 | 지난주 | 이번 주 |\n| --- | --- | --- |\n| 요청 | 309 | 357 |\n| 오류율 | 0% | 5.88% |\n| p95 | 2525ms | 2598ms |\n| 답 못 함 | 5.5% | 4.76% |\n| SLO | 못 지킴 unanswered_rate | 못 지킴 error_rate, unanswered_rate |\n\n## 문제\n\n- 실패 16건 · Search FAQ · timeout of 1000ms exceeded\n- 실패 5건 · Answer · 429 Rate limit reached for requests\n- 답하지 못한 질문 17건 · 와이파이\n- 이상 시간대 2026-10-26 09시 · 16/16 실패\n- 이상 시간대 2026-10-29 15시 · 5/7 실패\n\n## 요약 (LLM, 숫자 확인 통과)\n\n가장 많은 미응답 주제는 와이파이로 17건입니다. 가장 흔한 장애는 Search FAQ 노드에서 발생한 \"timeout of 1000ms exceeded\" 메시지로 16건입니다. 이상 징후가 가장 심한 시간대는 10월 26일 09시로 오류 16건, 전체 16건입니다.\n\n## 다음 할 일\n\n- FAQ에 '와이파이' 항목 추가\n- FAQ 검색 timeout · 재시도 설정 점검 (72일차)\n- LLM 사용량 한도 · 대체 경로 점검 (75 · 72일차)",
"total": 357,
"error_rate": 0.0588,
"slo_ok": false,
"numbers_ok": true
}
✔ 주간 보고 · 이상 시간대 · 1.8s
→ request POST /webhook/my-weekly
{
"from": "2026-10-26",
"to": "2026-10-30",
"prev_from": "2026-10-19",
"prev_to": "2026-10-23"
}
← response HTTP 200
{
"markdown": "# IT 헬프데스크 주간 운영 보고 (2026-10-26 ~ 2026-10-30)\n\n## 숫자\n\n| 지표 | 지난주 | 이번 주 |\n| --- | --- | --- |\n| 요청 | 309 | 357 |\n| 오류율 | 0% | 5.88% |\n| p95 | 2525ms | 2598ms |\n| 답 못 함 | 5.5% | 4.76% |\n| SLO | 못 지킴 unanswered_rate | 못 지킴 error_rate, unanswered_rate |\n\n## 문제\n\n- 실패 16건 · Search FAQ · timeout of 1000ms exceeded\n- 실패 5건 · Answer · 429 Rate limit reached for requests\n- 답하지 못한 질문 17건 · 와이파이\n- 이상 시간대 2026-10-26 09시 · 16/16 실패\n- 이상 시간대 2026-10-29 15시 · 5/7 실패\n\n## 요약 (LLM, 숫자 확인 통과)\n\n가장 많은 미응답 주제는 와이파이로 17건입니다. 가장 흔한 장애는 Search FAQ 노드에서 발생한 \"timeout of 1000ms exceeded\" 메시지로 16건입니다. 이상 징후가 가장 심한 시간대는 10월 26일 09시로, 총 16건 중 16건이 오류입니다.\n\n## 다음 할 일\n\n- FAQ에 '와이파이' 항목 추가\n- FAQ 검색 timeout · 재시도 설정 점검 (72일차)\n- LLM 사용량 한도 · 대체 경로 점검 (75 · 72일차)",
"total": 357,
"error_rate": 0.0588,
"slo_ok": false,
"numbers_ok": true
}
✔ 주간 보고 · 와이파이 · 1.7s
→ request POST /webhook/my-weekly
{
"from": "2026-10-26",
"to": "2026-10-30",
"prev_from": "2026-10-19",
"prev_to": "2026-10-23"
}
← response HTTP 200
{
"markdown": "# IT 헬프데스크 주간 운영 보고 (2026-10-26 ~ 2026-10-30)\n\n## 숫자\n\n| 지표 | 지난주 | 이번 주 |\n| --- | --- | --- |\n| 요청 | 309 | 357 |\n| 오류율 | 0% | 5.88% |\n| p95 | 2525ms | 2598ms |\n| 답 못 함 | 5.5% | 4.76% |\n| SLO | 못 지킴 unanswered_rate | 못 지킴 error_rate, unanswered_rate |\n\n## 문제\n\n- 실패 16건 · Search FAQ · timeout of 1000ms exceeded\n- 실패 5건 · Answer · 429 Rate limit reached for requests\n- 답하지 못한 질문 17건 · 와이파이\n- 이상 시간대 2026-10-26 09시 · 16/16 실패\n- 이상 시간대 2026-10-29 15시 · 5/7 실패\n\n## 요약 (LLM, 숫자 확인 통과)\n\n가장 많은 미응답 주제는 와이파이로 17건입니다. 가장 흔한 장애는 Search FAQ 노드에서 발생한 \"timeout of 1000ms exceeded\" 메시지로 16건입니다. 이상 징후가 가장 심한 시간대는 10월 26일 09시로, 총 16건 중 16건이 오류입니다.\n\n## 다음 할 일\n\n- FAQ에 '와이파이' 항목 추가\n- FAQ 검색 timeout · 재시도 설정 점검 (72일차)\n- LLM 사용량 한도 · 대체 경로 점검 (75 · 72일차)",
"total": 357,
"error_rate": 0.0588,
"slo_ok": false,
"numbers_ok": true
}
Passed 7/7
report: runs/lab03-challenge-20261031-075252.json
HTTP 200 · 1.9s
{
"markdown": "# IT 헬프데스크 주간 운영 보고 (2026-10-26 ~ 2026-10-30)\n\n## 숫자\n\n| 지표 | 지난주 | 이번 주 |\n| --- | --- | --- |\n| 요청 | 309 | 357 |\n| 오류율 | 0% | 5.88% |\n| p95 | 2525ms | 2598ms |\n| 답 못 함 | 5.5% | 4.76% |\n| SLO | 못 지킴 unanswered_rate | 못 지킴 error_rate, unanswered_rate |\n\n## 문제\n\n- 실패 16건 · Search FAQ · timeout of 1000ms exceeded\n- 실패 5건 · Answer · 429 Rate limit reached for requests\n- 답하지 못한 질문 17건 · 와이파이\n- 이상 시간대 2026-10-26 09시 · 16/16 실패\n- 이상 시간대 2026-10-29 15시 · 5/7 실패\n\n## 요약 (LLM, 숫자 확인 통과)\n\n가장 많은 미응답 주제는 와이파이로 17건입니다. 가장 흔한 장애는 Search FAQ 노드에서 발생한 \"timeout of 1000ms exceeded\" 메시지로 16건입니다. 가장 심각한 이상 시간대는 10월 26일 09시로 오류 16건, 전체 16건입니다.\n\n## 다음 할 일\n\n- FAQ에 '와이파이' 항목 추가\n- FAQ 검색 timeout · 재시도 설정 점검 (72일차)\n- LLM 사용량 한도 · 대체 경로 점검 (75 · 72일차)",
POST http://localhost:5678/webhook/my-slo-alert · 6 case(s) × 1
✘ 둘째 주 · SLO 못 지킴 → 알림 · 0.0s · status 404 (expected 200); ok = null (expected false); breaches = null (expected ["error_rate", "unanswered_rate"]); alert = null (expected sent); message has none of ['error_rate 0.0588 > 0.01']
→ request POST /webhook/my-slo-alert
{
"from": "2026-10-26",
"to": "2026-10-30"
}
← response HTTP 404
{
"code": 404,
"message": "The requested webhook \"POST my-slo-alert\" is not registered.",
"hint": "The workflow must be active for a production URL to run successfully. You can activate the workflow using the toggle in the top-right of the editor. Note that unlike test URL calls, production URL calls aren't shown on the canvas (only in the executions list)"
}
✘ 알림 확인 (high · slo) · 0.0s · workflow = null (expected slo); severity = null (expected high); reason = null (expected slo); message has none of ['unanswered_rate']
→ request POST http://localhost:8800/alerts/latest
{}
← response HTTP 200
{}
✘ 10분 안에 다시 확인 → 보내지 않음 · 0.0s · status 404 (expected 200); ok = null (expected false); alert = null (expected suppressed)
→ request POST /webhook/my-slo-alert
{
"from": "2026-10-26",
"to": "2026-10-30"
}
← response HTTP 404
{
"code": 404,
"message": "The requested webhook \"POST my-slo-alert\" is not registered.",
"hint": "The workflow must be active for a production URL to run successfully. You can activate the workflow using the toggle in the top-right of the editor. Note that unlike test URL calls, production URL calls aren't shown on the canvas (only in the executions list)"
}
✘ slo 알림은 1개 · 0.0s · count = 0 (expected 1)
→ request POST http://localhost:8800/alerts/list
{
"workflow": "slo"
}
← response HTTP 200
{
"count": 0,
"alerts": []
}
✘ 기준 안이면 알림 없음 · 0.0s · status 404 (expected 200); ok = null (expected true); breaches = null (expected []); alert = null (expected none)
→ request POST /webhook/my-slo-alert
{
"from": "2026-10-19",
"to": "2026-10-23",
"slo": {
"unanswered_rate": 0.06
}
}
← response HTTP 404
{
"code": 404,
"message": "The requested webhook \"POST my-slo-alert\" is not registered.",
"hint": "The workflow must be active for a production URL to run successfully. You can activate the workflow using the toggle in the top-right of the editor. Note that unlike test URL calls, production URL calls aren't shown on the canvas (only in the executions list)"
uv run tools/flow.py test cases/replay-after.json && uv run tools/flow.py test cases/replay-normal.json && uv run tools/flow.py test cases/lab03-cost.json -v
uv run tools/flow.py push answers/77-lab03-challenge-weekly.json answers/77-lab03-challenge2-slo-alert.json
uv run tools/flow.py test cases/lab03-challenge.json && uv run tools/flow.py test cases/lab03-challenge2.json -v
uv run tools/flow.py ops --reset && uv run tools/flow.py doctor
```
- 결과의 ✔ · ✘(판정)는 같게 나와야 합니다. 두 주 기록의 지표는 늘 같고, 시간 · LLM 요약 글 · 오늘 실습 기록의 단계 시간은 다를 수 있습니다.