- 목표: Lab 02에서 찾은 문제 둘(FAQ 검색 timeout, 와이파이 FAQ 없음)을 **고치고**, 같은 질문을 **다시 돌려서** 고친 효과를 숫자로 확인한다. 운영 기준(SLO)으로 판정하고, 고친 것의 대가(느려짐)를 재고, 주간 보고와 SLO 알림을 자동으로 만든다.
> 복사해 붙일 요청문은 없습니다. 막히면 `▶` 를 하나씩 펼칩니다. 오늘 실습에서 남기는 기록은 `source: live`이고 `tag`(`before` · `after` · `normal`)로 나눕니다. 연습이 끝나면 `uv run tools/flow.py ops --reset`.
## 예제 1 · 고치기 전 · 후를 같은 질문으로 (14분)
### 이 실습의 의도
**한 줄로:** 두 주 동안 쓰던 헬프데스크로 월요일 아침처럼 FAQ가 느린 상황을 **다시 만들어** 기록을 남기고(`before`), Lab 02의 두 문제를 고친 뒤 **같은 질문**을 다시 보내(`after`) 내 보고서로 전 · 후를 비교합니다.
> **생활 속 예 · 카드 단말기 설정과 들여놓을 물건.** 월요일 아침 카드 단말기가 느려서 결제가 줄줄이 실패했고, 손님들은 없는 물건(와이파이 공유기)을 계속 찾았습니다. 단말기의 "기다리는 시간" 설정은 직원이 바꾸고, 없는 물건은 구매 담당이 들여놓습니다. 고친 뒤에는 **같은 손님 열 명**을 다시 받아 보고 정말 나아졌는지 장부로 확인합니다. 예제 1은 이 "고치기 전 → 고치기(두 사람) → 같은 손님으로 다시"를 하는 실습입니다.
| 단계 | 하는 일 | 남는 기록 |
| --- | --- | --- |
| ① 고치기 전 (에이전트 없이) | 제공 헬프데스크를 복사해 push, 느린 FAQ(1.2초)에서 질문 10개 | `tag before` 10줄 |
| ② 고치기 | 워크플로우: FAQ 검색 timeout · 재시도 (에이전트) · 데이터: 와이파이 FAQ 더하기 (나) | — |
| ③ 고친 뒤 | 같은 느린 FAQ에서 같은 10개 | `tag after` 10줄 |
| 비교 | 내 보고서에 `tag`로 물음 (`cases/lab03.json`) | — |
**끝나면 알게 되는 것.** 고친 효과는 **같은 조건 · 같은 질문**으로 다시 재야 알 수 있다는 것, 그리고 문제마다 고치는 곳(워크플로우 · 데이터)과 고치는 사람이 다르다는 것.
**적을 곳.**`my-work/OPS.md` 4.1 표 (고친 것 · 어디서 · 누가 · 고치기 전 · 고친 뒤).
uv run tools/flow.py test cases/replay-before.json -v # 느린 FAQ(1.2초)에서 10개, tag before
uv run tools/flow.py logs --tag before --source live --last 3
uv run tools/flow.py test cases/lab03.json -v # 보고서로 비교 (고친 뒤 기록은 아직 없음)
```
### 이해하기
**다시 돌려 보기(replay).** 운영 기록으로 문제를 찾았다면, 그 상황을 **다시 만들어** 고치기 전과 후를 같은 조건에서 잽니다. 오늘은 고장 스위치(`fault faq slow`, 1.2초)로 월요일 아침의 느린 FAQ를 만들고, 같은 질문 10개를 보냅니다. 조건이 다르면(FAQ가 빠른 날 고친 뒤를 재면) 고친 효과인지 운인지 알 수 없습니다.
| 와이파이 FAQ가 없음 (34건) | 데이터 API의 FAQ (`requests/faq-wifi.json`) | 나 (`faq/add`) | 콘텐츠 — 워크플로우를 아무리 고쳐도 없는 답은 못 함 |
**`tag`로 나누기.** 헬프데스크는 본문의 `tag`를 기록에 그대로 남깁니다. 보고서에 `{"tag": "before", "source": "live"}`로 물으면 고치기 전 10줄만 셉니다. 두 주 기록(`seed`)과 섞이지 않게 `source: live`도 함께.
**`replay-before`가 10/10인 까닭.** 이 테스트는 질문을 보내고 "200이 오나"만 봅니다 (헬프데스크는 실패해도 "담당자에게 연결합니다"로 답함). 실패했는지는 **기록**과 **보고서**로 봅니다 — 사용자에게 보인 답과 실제로 일어난 일을 나눠 보는 것은 76일차와 같습니다.
✔ 고친 뒤 · 답하지 못한 주제 없음 · 0.0s · 0 calls · $0.000000
Passed 3/4
```
**왜 이렇게 나왔나 (고치기 전)**
- **`replay-before` 10/10인데 기록은 10건 모두 오류:** 테스트는 처음에 오늘 기록 · 더한 FAQ를 비우고, FAQ를 1.2초 느리게 만든 뒤(`before` 세 줄) 질문을 보냅니다. 헬프데스크는 실패해도 "지금은 답할 수 없어 담당자에게 연결합니다"로 **200을 줍니다.** 그래서 테스트는 ✔이지만, 기록에는 `error` · `Search FAQ` · 약 1030ms(1초 timeout + 처리)가 남았습니다. 사용자에게 보인 것과 실제로 일어난 일을 나눠 보는 까닭입니다.
- 끝의 `after` 줄은 테스트가 고장 스위치를 `ok`로 되돌린 것입니다.
- **`lab03` 3/4:** 내 보고서에 `{"tag": "before", "source": "live"}`로 물어 "10건 모두 실패 · 원인 FAQ timeout 10건"이 ✔. "고친 뒤 · 오류 없음"은 고친 뒤 기록이 아직 0건이라 ✘(`total = 0`). "답하지 못한 주제 없음"은 0건이라 목록이 비어 **우연히** ✔입니다 — 고친 뒤 기록이 생긴 다음에 의미가 있습니다.
- 이 10건은 Lab 02에서 찾은 월요일 아침(09시 16건 모두 FAQ timeout)을 그대로 다시 만든 것입니다. 예상한 결과.
| 와이파이 질문 5개 | 오류 | 자동 답변 (`CORP-WIFI` · `사번`) | FAQ-007을 데이터에 더함 |
| 한 건 시간 | 1.1~2.1초 | **2.3~4.5초** | FAQ 1.2초를 기다린 뒤 LLM 답 |
- **두 고침이 다 필요했습니다.** timeout만 늘렸다면 와이파이 질문 5개는 FAQ에 없어 `담당자 연결`이 됐을 것이고("답하지 못한 주제 없음" ✘), FAQ만 더했다면 1초에 끊겨 10개 모두 오류였을 것입니다. 하나는 워크플로우(에이전트), 하나는 콘텐츠(나)입니다.
- **첫 `before` 줄 `logs-reset` · `{"tag": "after"}`:** 테스트가 지난번 `after` 기록**만** 지우고 시작합니다 (`before` 기록 10줄은 그대로). 그래서 고치기 전에 `replay-after`를 한 번 돌려 실패했거나 여러 번 돌려도, 마지막 한 번의 10줄만 남아 `lab03`이 그 10줄로 셉니다. 처음 돌리면 `{"cleared": 0}`, 다시 돌리면 `{"cleared": 10}`. 예제 3의 `replay-normal`도 같은 방식(`tag: normal`)입니다.
- **`replay-after` 10/10은 `replay-before`와 뜻이 다릅니다.** 이번 테스트는 200만이 아니라 `route: 자동 답변` · `status: success`(와이파이는 답에 `CORP-WIFI`까지)를 확인합니다.
- **`10 calls · $0.000000`:** 고친 뒤 10건은 LLM을 한 번씩 불렀습니다. 제공 헬프데스크는 기록에 비용을 0으로 남기므로 `$0.000000`입니다 (두 주 기록에는 비용이 있음).
- **대신 느려졌습니다** (2.3~4.5초). 예제 2의 SLO와 예제 3에서 이 대가를 잽니다.
## 예제 2 · SLO로 판정하기 (8분)
### 이 실습의 의도
**한 줄로:** 보고서에 `unanswered_rate`와 `slo`(기준을 넘은 지표 `breaches`, 지켰는지 `ok`)를 더해, 매주 "약속을 지켰나"를 숫자 하나로 답하게 합니다.
> **생활 속 예 · "30분 안에 배달" 약속.** 피자 가게가 "빠르게 배달합니다"라고만 하면 늦어도 할 말이 없습니다. "30분 안에, 아니면 할인"이라고 **숫자로 약속**하면 매일 지켰는지가 분명해집니다. 예제 2는 헬프데스크에 "오류율 1% · 95%는 3초 안 · 답 못 함 2%"라는 약속을 정하고, 보고서가 지켰는지 판정하게 하는 실습입니다.
| 지표 | 기본 기준 (limits) | 둘째 주 (Lab 01 · 02에서) |
| --- | --- | --- |
| `error_rate` | 0.01 (1%) | 0.0588 |
| `p95_ms` | 3000 | 2598 |
| `unanswered_rate` | 0.02 (2%) | ? (이번에 더함) |
**끝나면 알게 되는 것.** SLO가 지표를 "좋다 · 나쁘다"에서 "지켰다 · 못 지켰다"로 바꾼다는 것, 기준은 본문으로 바꿀 수 있어야 한다는 것(누가 정하나), 그리고 고친 뒤에도 **다른 지표가 새로 어길 수 있다**는 것.
**적을 곳.**`my-work/OPS.md` 5절 SLO 표.
```bash
uv run tools/flow.py test cases/lab03-slo.json -v # 고치기 전
```
| 조건 | 값 |
| --- | --- |
| 기본 기준 | 오류율 0.01 · p95 3000ms · 답 못 함 0.02 ([AGENTS.md](AGENTS.md) 3절), 본문 `slo`로 바꿀 수 있음 |
| 결과 | `unanswered_rate`, `slo: {ok, breaches, limits}` |
| 기대 결과 | `cases/lab03-slo.json` |
### 이해하기
**SLO(Service Level Objective, 서비스 수준 목표).** 사용자가 겪는 품질을 지표 하나와 숫자 하나로 정한 약속입니다. "빠르면 좋다"가 아니라 "p95 3초 안"처럼 정하면, 매주 지켰는지가 분명해지고 무엇부터 고칠지(어긴 지표)도 정해집니다. 기준은 사용자 · 팀장 · 비용(75일차)이 함께 정합니다.
- **둘째 주는 두 약속을 어겼습니다:** 오류율 5.88%(기준 1%)와 답 못 함 4.76%(기준 2%). p95 2598ms는 3초 안입니다. Lab 02의 문제 둘(FAQ timeout · 와이파이)이 그대로 SLO 두 개에 대응합니다.
- **첫 주에도 답 못 함은 어겼습니다** (5.5%). 와이파이 FAQ는 첫 주에도 없었습니다. 기준을 0.06으로 바꾸면 지킨 것이 됩니다 — 같은 기록, 다른 약속. 기준을 바꾸는 것은 숫자 하나지만, **누가 · 왜** 바꾸는지가 중요합니다.
- **고친 뒤에는 새 약속을 어겼습니다.** 오류 0 · 답 못 함 0으로 두 약속은 지켰지만, p95가 **3560ms**로 3초를 넘었습니다. `steps`를 보면 FAQ 단계 p50이 1238ms — 느린 FAQ를 1.2초씩 기다렸기 때문입니다. 고침이 문제 하나를 다른 지표로 옮겼습니다 (예제 3).
-`lab02-challenge` 5/5: 앞의 칸은 그대로입니다.
## 예제 3 · 고친 것의 대가 (6분, 에이전트 없이)
### 이 실습의 의도
**한 줄로:** 예제 2에서 고친 뒤 기록이 p95를 어긴 까닭을 **단계 시간**(Lab 01 과제 2의 `steps`)으로 확인합니다. FAQ를 평소대로 돌려 같은 10개를 한 번 더 보내(`normal`), 느린 FAQ에서의 고친 뒤와 비교합니다.
> **생활 속 예 · 단말기 대기 시간을 늘린 대가.** 카드 단말기가 느린 날 "기다리는 시간"을 늘렸더니 결제 실패는 사라졌지만, 손님마다 계산이 1초씩 길어져 줄이 늘었습니다. 단말기가 정상인 날에는 기다릴 일이 없어 빠릅니다. 고친 것이 문제를 없앤 것인지, 다른 곳으로 옮긴 것인지 구분해야 합니다. 예제 3은 같은 손님 열 명을 "단말기가 느린 날"과 "정상인 날"에 받아 보고 비교하는 실습입니다.
| 기록 (`tag`) | FAQ | 헬프데스크 | 볼 것 |
| --- | --- | --- | --- |
| `before` | 느림 (1.2초) | 고치기 전 (timeout 1초) | 오류 · FAQ 단계 시간 |
| `after` | 느림 (1.2초) | 고친 뒤 (timeout 3초) | 오류 0, 대신 FAQ 단계 시간은? |
| `normal` (이번에) | 평소 | 고친 뒤 | FAQ 단계 시간 · p95 |
**끝나면 알게 되는 것.** timeout을 늘린 것은 "느린 FAQ를 **견디는**" 고침이지 "**빠르게** 하는" 고침이 아니라는 것. 고친 뒤에는 새로 나빠진 것을 찾아 함께 보고해야 한다는 것.
**적을 곳.**`my-work/OPS.md` 4.2 표 (기록 · FAQ 상태 · 오류 · FAQ 단계 p50 · p95)와 "새로 나빠진 것과 그 까닭".
```bash
uv run tools/flow.py test cases/replay-normal.json -v # FAQ 평소, 같은 10개, tag normal
uv run tools/flow.py test cases/lab03-cost.json -v # 세 기록을 단계 시간으로 비교
uv run tools/flow.py ops
```
### 이해하기
**전체 시간 = 단계 시간의 합.** 고친 뒤 한 번의 실행은 "FAQ를 기다린 시간 + LLM이 답한 시간"입니다. FAQ가 1.2초 느리면, 고친 헬프데스크는 그 1.2초를 **기다려 줍니다.** 그래서 오류는 사라지지만 전체 시간이 늘어 p95가 기준(3초)을 넘을 수 있습니다.
```mermaid
flowchart LR
subgraph after["after · FAQ 느림"]
A1["FAQ ≈ 1.2초"] --> A2["답 ≈ 1초"]
end
subgraph normal["normal · FAQ 평소"]
N1["FAQ ≈ 수십 ms"] --> N2["답 ≈ 1초"]
end
```
**왜 범위(range)로 확인하나.** 오늘 실습 기록의 시간은 실행마다 다릅니다. 그래서 `lab03-cost`는 "FAQ 단계 p50이 1150~3500ms 사이"처럼 **범위**로 봅니다. 두 주 기록처럼 늘 같은 숫자가 아니기 때문입니다.
**진짜 고침은 어디에.** FAQ 검색이 느린 원인(데이터 API · 검색 서버)을 고치는 것은 다른 팀의 일입니다. 오늘의 timeout은 그동안 사용자에게 "실패" 대신 "늦은 답"을 주는 **임시 조치**입니다. 보고서에는 둘을 나눠 적습니다.
- **늘어난 시간은 모두 FAQ 단계에서 왔습니다.** 답 단계는 1103ms · 997ms로 비슷합니다. `after`의 FAQ 단계 1238ms는 느린 FAQ의 1.2초를 그대로 기다린 시간입니다.
- **고친 것은 "견디기"였습니다.** timeout을 늘려 느린 FAQ에서도 실패하지 않게 했지만, 사용자는 그만큼 더 기다립니다. FAQ가 평소대로면 같은 헬프데스크가 17ms 만에 FAQ를 받고 SLO도 지킵니다. 진짜 고칠 곳은 FAQ 검색이 느려지는 원인(다른 팀)입니다.
- **`ops`의 30줄**은 세 기록이 `tag`로 나뉘어 있다는 표시입니다. 같은 헬프데스크 · 같은 질문이라도 `tag`가 다르니 보고서에서 섞이지 않습니다.
-`OPS.md` 4.2에 이 표와 "새로 나빠진 것: p95, 까닭: 느린 FAQ를 기다림"을 적습니다.
## 과제 1 · 주간 보고 (12분)
### 이 실습의 의도
**한 줄로:** 만든 보고서 · 요약을 **다시 불러** 매주 월요일 회의에 그대로 붙일 주간 보고(마크다운)를 만듭니다. 숫자 · 문제는 Code가, 요약은 LLM이, 다음 할 일은 규칙이 씁니다.
> **생활 속 예 · 주간 매출 보고서.** 가게 점장은 매주 "지난주 · 이번 주 매출표, 문제 세 가지, 세 줄 요약, 다음 주 할 일"을 본사에 보냅니다. 매주 같은 칸에 같은 방식으로 채우니 본사는 표만 보고도 비교합니다. "할 일"은 정해진 규칙(재고가 없으면 주문, 단말기 고장이면 수리 요청)대로 씁니다. 과제 1은 이 보고서를 자동으로 만드는 실습입니다.
> "매주 월요일 회의에 쓸 주간 보고를 자동으로 만들어 주세요. 지난주와 비교한 숫자, 문제 목록, 세 문장 요약, 다음 할 일. 그대로 붙여 넣을 수 있게 마크다운으로요."
| 재료 | `my-log-report`(이번 주 · 지난주), `my-log-summary` — **만든 것을 다시 부른다** |
| 결과 | `markdown`(절: `## 숫자` · `## 문제` · `## 요약` · `## 다음 할 일`), `total`, `error_rate`, `slo_ok`, `numbers_ok` |
| 기대 결과 | `cases/lab03-challenge.json` |
**먼저 생각해 보기 (2분)**: "다음 할 일"을 LLM이 쓸까요, 규칙이 쓸까요? 문제 목록에서 정해진 할 일로 이어지는 것은 무엇인가요?
```bash
uv run tools/flow.py test cases/lab03-challenge.json -v # 고치기 전 (웹훅이 아직 없음)
```
### 이해하기
**조립(composition).** 주간 보고는 새로 계산하지 않습니다. 이미 테스트로 확인한 웹훅 셋을 부르고(이번 주 보고서 · 지난주 보고서 · 요약), 받은 것을 표와 목록으로 **조립**만 합니다. 정의는 늘 한 곳이고, 보고서를 고치면 주간 보고도 함께 바뀝니다.
```mermaid
flowchart LR
W(["from · to ·<br/>prev_from · prev_to"]) --> T["This week<br/>my-log-report"] --> P["Last week<br/>my-log-report"] --> S["Summary<br/>my-log-summary"] --> C["Write report (Code)<br/>표 · 문제 · 요약 · 할 일"] --> O(["markdown"])
```
**누가 무엇을 쓰나.**
| 절 | 누가 | 왜 |
| --- | --- | --- |
| 숫자 (표) | Code | 숫자는 보고서 그대로, 사람이 읽게 `5.88%` |
| 문제 | Code | 실패 · 답 못 한 주제 · 이상 시간대를 목록으로 |
| 요약 | LLM (+ 숫자 확인) | 사람의 말로 — 확인 결과를 함께 |
| 다음 할 일 | 규칙 (Code) | "와이파이가 답 못 함 1위 → FAQ 추가"처럼 정해진 연결 |
**기대 결과.** 고치기 전 0/7 (404), 고친 뒤 7/7. 한 번 부르는 데 2~4초 (보고서 둘 + LLM 하나).
<details><summary>▶ 1단계 · 다시 쓰지 말고 부르기</summary>
지표 계산을 또 쓰면 정의가 두 벌이 됩니다. 이미 있는 웹훅을 HTTP로 부릅니다 (AGENTS.md 5절 "다른 내 웹훅을 부르기"). 세 웹훅이 모두 push돼 있어야 합니다.
</details>
<details><summary>▶ 2단계 · 표의 모양</summary>
`| 요청 | 309 | 357 |`처럼 지난주 · 이번 주를 나란히. 이상 시간대 `2026-10-26T09`는 사람이 읽게 `2026-10-26 09시`로.
가장 많은 미응답 주제는 와이파이로 17건입니다. 가장 흔한 장애는 Search FAQ 노드에서 발생한 "timeout of 1000ms exceeded" 메시지로 16건입니다. 가장 심각한 이상 시간대는 10월 26일 09시로 오류 16건, 전체 16건입니다.
## 다음 할 일
- FAQ에 '와이파이' 항목 추가
- FAQ 검색 timeout · 재시도 설정 점검 (72일차)
- LLM 사용량 한도 · 대체 경로 점검 (75 · 72일차)
```
**고친 뒤 이렇게 나온 까닭**
| 절 | 어디서 왔나 | 이 보고에서 |
| --- | --- | --- |
| 숫자 | 이번 주 · 지난주 `my-log-report` | 요청 309 → 357, 오류율 0% → 5.88% (`0.0588` → `5.88%`) |
| 문제 | 이번 주 보고서의 `failures` · `unanswered_topics` · `anomalies` | Lab 02에서 찾은 다섯 줄 그대로 |
| 요약 | `my-log-summary` (숫자 확인 통과) | 17 · 16 · 10월 26일 09시 |
| 다음 할 일 | 규칙 | 와이파이가 답 못 함 1위 → FAQ 추가, `Search FAQ` 실패 → timeout, 429 → 사용량 한도 |
- **지난주와 나란히 보니** 이번 주가 무엇이 나빠졌는지 바로 보입니다: 오류율이 0에서 5.88%로, SLO 위반이 하나에서 둘로. 답 못 함은 5.5%에서 4.76%로 조금 줄었지만 여전히 기준(2%) 위입니다.
- **다음 할 일 셋은 LLM이 쓴 것이 아닙니다.** 문제 목록에서 정해진 할 일로 이어지는 연결을 규칙으로 썼으니, 매주 같은 문제에는 같은 할 일이 나옵니다. 그리고 그 셋이 바로 Lab 03 예제 1에서 한 일(와이파이 FAQ · timeout)과 남은 일(429)입니다.
- **2~4초:** 보고서 두 번(각 0.1초) + 요약(LLM 한 번). 요약 글은 Lab 02 과제 2와 조금 다르지만 숫자 확인은 통과했습니다.
## 과제 2 · SLO를 어기면 알림 (10분)
### 이 실습의 의도
**한 줄로:** 기간을 받아 보고서의 SLO를 확인하고, **어겼으면** 76일차 알림 API에 high 알림을 남기되, 같은 알림을 10분 안에 또 보내지 않습니다.
> **생활 속 예 · 냉장고 온도 경보.** 가게 냉장고가 기준 온도를 넘으면 경보가 울려야 합니다. 하지만 1분마다 계속 울리면 직원은 곧 꺼 버립니다. 그래서 "한 번 울리고, 10분 안에는 다시 울리지 않되, 기록에는 남긴다"로 정합니다. 기준 안이면 울리지 않습니다. 과제 2는 SLO를 냉장고 온도처럼 지켜보는 경보를 만드는 실습입니다.
> "주간 보고는 월요일에나 봐요. SLO를 어기면 바로 알 수 있게 알림을 남겨 주세요. 대신 같은 걸로 계속 울리면 안 됩니다."
D -->|있음 · 최근 알림 없음| A["POST /alerts<br/>high · slo"] --> T(["sent"])
```
**알림 피로(alert fatigue).** 같은 원인으로 알림이 계속 오면 사람은 알림을 읽지 않게 되고, 정말 새로운 알림도 놓칩니다 (76일차). 그래서 같은 이유(`reason: slo`)의 알림이 10분 안에 있으면 보내지 않고, 대신 결과에 `suppressed`를 남겨 "확인은 했다"는 기록은 지킵니다.
**메시지에 숫자를.** "SLO 위반"만으로는 무엇을 할지 모릅니다. `SLO breach: error_rate 0.0588 > 0.01, unanswered_rate 0.0476 > 0.02`처럼 **어느 지표가 · 얼마로 · 기준이 얼마인데** 넘었는지를 한 줄에.
`cases/lab03-challenge2.json` 맨 위 `before`가 `/alerts-clear`를 부릅니다. 그래서 첫 케이스는 늘 `sent`, 같은 기간을 다시 물은 셋째 케이스는 `suppressed`여야 합니다. 워크플로우 안에서는 알림을 지우지 않습니다.
✔ live run logs, added FAQ, created tickets, DLQ and alerts emptied, fault switch all ok
```
**고친 뒤 이렇게 나온 까닭**
| 순서 | 물은 것 | 결과 | 까닭 |
| --- | --- | --- | --- |
| 1 | 둘째 주 | `sent` | 두 지표를 어겼고, 10분 안의 `slo` 알림이 없음 |
| 2 | 알림 확인 | high · `slo` · 메시지에 두 지표 | 1에서 남긴 알림 |
| 3 | 둘째 주 다시 | **`suppressed`** | 10분 안에 같은 알림(1)이 있음 |
| 4 | 알림 수 | 1 | 3은 보내지 않았음 |
| 5 | 첫 주 · 기준 0.06 | `none` | 어긴 지표가 없음 |
| 6 | 알림 수 | 1 | 5도 보내지 않았음 |
- **메시지 한 줄로 무엇을 할지 압니다:** `error_rate 0.0588 > 0.01, unanswered_rate 0.0476 …` — 어느 지표가 얼마로, 기준이 얼마인데 넘었는지. `ops`는 한 줄을 60자로 줄여 보여 줘서 뒤가 잘렸습니다 (전체는 `unanswered_rate 0.0476 > 0.02`).
- **`suppressed`도 결과입니다.** 같은 문제로 다시 확인한 것은 기록에 남고, 사람에게는 한 번만 갑니다. 10분이 지나도 어긴 상태라면 다시 `sent`가 됩니다.
- **1.0초 · 0.3초:** 보고서를 부르고(0.1초) 알림을 읽고 쓰는 것뿐이라 빠릅니다. n8n의 Schedule 트리거로 10분마다 돌려도 부담이 없습니다 (79일차 Ops Assistant로 이어짐).
- 마지막 `ops --reset`으로 오늘 기록 30줄 · 더한 FAQ · 알림을 비웠습니다.