$ uv run tools/flow.py push reference/lab03-example2-canary.json ! unpublished '74 IT helpdesk + broken release check (answer)' (w86d00ad9781296e): it used the same webhook path ✔ pushed '74 IT helpdesk + canary (reference)' (id w2e1e5fc96604a25) POST http://localhost:5678/webhook/my-helpdesk $ uv run tools/flow.py test cases/lab03-canary.json -v ✔ before: POST http://localhost:8800/releases/helpdesk/reset · HTTP 200 · 0.0s · {"name": "helpdesk", "active": "1.0.0", "canary": null, "require_gate": false, "releases": {"1.0.0": {"prompt_version": → request POST http://localhost:8800/releases/helpdesk/reset {} ← response HTTP 200 { "name": "helpdesk", "active": "1.0.0", "canary": null, "require_gate": false, "releases": { "1.0.0": { "prompt_version": "p1", "model": "gpt-4.1-mini", "note": "첫 릴리스" }, "1.1.0": { "prompt_version": "p2", "model": "gpt-4.1-mini", "note": "FAQ 답 끝에 출처 번호" }, "1.2.0": { "prompt_version": "p3", "model": "gpt-4.1-mini", "note": "답을 한 문장으로 짧게" }, "2.0.0": { "prompt_version": "p2", "model": "gpt-5.4-nano", "note": "더 작은 모델 (비용)" }, "2.1.0": { "prompt_version": "p9", "model": "gpt-4.1-mini", "note": "출처 번호 · 존댓말 다듬기 (지시문 이름 확인 필요)" } } } ✔ before: POST http://localhost:8800/releases/helpdesk · HTTP 200 · 0.0s · {"name": "helpdesk", "active": "1.0.0", "canary": {"release": "1.1.0", "percent": 50}, "require_gate": false, "releases" → request POST http://localhost:8800/releases/helpdesk { "canary": { "release": "1.1.0", "percent": 50 } } ← response HTTP 200 { "name": "helpdesk", "active": "1.0.0", "canary": { "release": "1.1.0", "percent": 50 }, "require_gate": false, "releases": { "1.0.0": { "prompt_version": "p1", "model": "gpt-4.1-mini", "note": "첫 릴리스" }, "1.1.0": { "prompt_version": "p2", "model": "gpt-4.1-mini", "note": "FAQ 답 끝에 출처 번호" }, "1.2.0": { "prompt_version": "p3", "model": "gpt-4.1-mini", "note": "답을 한 문장으로 짧게" }, "2.0.0": { "prompt_version": "p2", "model": "gpt-5.4-nano", "note": "더 작은 모델 (비용)" }, "2.1.0": { "prompt_version": "p9", "model": "gpt-4.1-mini", "note": "출처 번호 · 존댓말 다듬기 (지시문 이름 확인 필요)" } } } POST http://localhost:5678/webhook/my-helpdesk · 6 case(s) × 1 ✔ 최유진 (bucket 0) → 카나리 · 2.8s → request POST /webhook/my-helpdesk { "question": "프린터 출력이 안 돼요", "user": "최유진" } ← response HTTP 200 { "route": "자동 답변", "answer": "프린터 전원과 네트워크 연결을 확인하고, 인쇄 대기열을 비운 뒤 다시 출력해 보시기 바랍니다. 추가 도움이 필요하면 담당 직원이 도와드리겠습니다. [FAQ-004]", "sources": [ "FAQ-004" ], "version": { "release": "1.1.0", "prompt_version": "p2", "model": "gpt-4.1-mini", "channel": "canary", "prompt_source": "registry" } } ✔ 정우성 (bucket 42) → 카나리 · 1.4s → request POST /webhook/my-helpdesk { "question": "VPN 접속이 자꾸 끊겨요. 어떻게 하나요?", "user": "정우성" } ← response HTTP 200 { "route": "자동 답변", "answer": "VPN 접속 오류는 VPN 클라이언트를 최신 버전으로 업데이트하고, 인증서 만료 여부를 확인한 뒤 다시 접속하시기 바랍니다. 추가 도움이 필요하면 문의해 주세요. [FAQ-003]", "sources": [ "FAQ-003" ], "version": { "release": "1.1.0", "prompt_version": "p2", "model": "gpt-4.1-mini", "channel": "canary", "prompt_source": "registry" } } ✔ 이준호 (bucket 56) → 운영 · 1.1s → request POST /webhook/my-helpdesk { "question": "VPN 접속이 자꾸 끊겨요. 어떻게 하나요?", "user": "이준호" } ← response HTTP 200 { "route": "자동 답변", "answer": "VPN 접속 오류는 VPN 클라이언트를 최신 버전으로 업데이트하고, 인증서 만료 여부를 확인한 뒤 다시 접속하시기 바랍니다. 현재 접수된 문의 건이 없어 추가 지원이 필요하시면 IT 담당자에게 문의해 주세요.", "sources": [ "FAQ-003" ], "version": { "release": "1.0.0", "prompt_version": "p1", "model": "gpt-4.1-mini", "channel": "stable", "prompt_source": "registry" } } ✔ 김민지 (bucket 80) → 운영 · 1.1s → request POST /webhook/my-helpdesk { "question": "메일함 용량이 꽉 찼대요", "user": "김민지" } ← response HTTP 200 { "route": "자동 답변", "answer": "메일함 용량이 초과된 경우, 오래된 메일과 큰 첨부 파일을 보관함으로 옮기거나 삭제하여 용량을 확보하시기 바랍니다. 현재 접수된 관련 문의는 없습니다. 추가 도움이 필요하시면 담당 직원이 도와드리겠습니다.", "sources": [ "FAQ-005" ], "version": { "release": "1.0.0", "prompt_version": "p1", "model": "gpt-4.1-mini", "channel": "stable", "prompt_source": "registry" } } ✔ 고정이 카나리보다 먼저 · 1.1s → request POST /webhook/my-helpdesk { "question": "프린터 출력이 안 돼요", "user": "최유진", "release": "1.0.0" } ← response HTTP 200 { "route": "자동 답변", "answer": "프린터 전원과 네트워크 연결을 확인하고, 인쇄 대기열을 비운 뒤 다시 출력해 보시기 바랍니다. 현재 접수된 관련 문의는 없으며, 추가 도움이 필요하시면 직원이 도와드리겠습니다.", "sources": [ "FAQ-004" ], "version": { "release": "1.0.0", "prompt_version": "p1", "model": "gpt-4.1-mini", "channel": "pinned", "prompt_source": "registry" } } ✔ 같은 사람은 늘 같은 쪽 · 1.3s → request POST /webhook/my-helpdesk { "question": "프린터 출력이 안 돼요", "user": "최유진" } ← response HTTP 200 { "route": "자동 답변", "answer": "프린터 전원과 네트워크 연결을 확인하고, 인쇄 대기열을 비운 뒤 다시 출력해 보시기 바랍니다. 추가 도움이 필요하면 담당 직원이 도와드리겠습니다. [FAQ-004]", "sources": [ "FAQ-004" ], "version": { "release": "1.1.0", "prompt_version": "p2", "model": "gpt-4.1-mini", "channel": "canary", "prompt_source": "registry" } } Passed 6/6 report: runs/lab03-canary-20261027-184226.json ✔ after: POST http://localhost:8800/releases/helpdesk/reset · HTTP 200 · 0.0s · {"name": "helpdesk", "active": "1.0.0", "canary": null, "require_gate": false, "releases": {"1.0.0": {"prompt_version": → request POST http://localhost:8800/releases/helpdesk/reset {} ← response HTTP 200 { "name": "helpdesk", "active": "1.0.0", "canary": null, "require_gate": false, "releases": { "1.0.0": { "prompt_version": "p1", "model": "gpt-4.1-mini", "note": "첫 릴리스" }, "1.1.0": { "prompt_version": "p2", "model": "gpt-4.1-mini", "note": "FAQ 답 끝에 출처 번호" }, "1.2.0": { "prompt_version": "p3", "model": "gpt-4.1-mini", "note": "답을 한 문장으로 짧게" }, "2.0.0": { "prompt_version": "p2", "model": "gpt-5.4-nano", "note": "더 작은 모델 (비용)" }, "2.1.0": { "prompt_version": "p9", "model": "gpt-4.1-mini", "note": "출처 번호 · 존댓말 다듬기 (지시문 이름 확인 필요)" } } } $ uv run tools/flow.py test cases/lab02.json ✔ before: POST http://localhost:8800/releases/helpdesk/reset · HTTP 200 · 0.0s · {"name": "helpdesk", "active": "1.0.0", "canary": null, "require_gate": false, "releases": {"1.0.0": {"prompt_version": POST http://localhost:5678/webhook/my-helpdesk · 5 case(s) × 1 ✔ 운영 중인 릴리스 (active) · 1.6s ✔ 후보 시험 · 1.1.0 고정 · 1.3s ✔ 후보 시험 · 2.0.0 (작은 모델) · 1.4s ✔ 없는 릴리스 · 0.1s ✔ 빈 질문 · 0.1s Passed 5/5 report: runs/lab02-20261027-184231.json $ uv run tools/flow.py test cases/lab02-challenge2.json ✔ before: POST http://localhost:8800/releases/helpdesk/reset · HTTP 200 · 0.0s · {"name": "helpdesk", "active": "1.0.0", "canary": null, "require_gate": false, "releases": {"1.0.0": {"prompt_version": POST http://localhost:5678/webhook/my-helpdesk · 5 case(s) × 1 ✔ 망가진 릴리스 2.1.0 · 400 release broken · 0.1s ✔ 평소 · 1.1.0은 저장소의 p2 · 1.2s ✔ before: POST http://localhost:8800/admin/fault · HTTP 200 · 0.0s · {"faq": "ok", "tickets": "ok", "prompts": "error", "slow_seconds": 8.0} ✔ 저장소 고장 · 1.1.0도 기본 지시문으로 · 1.2s ✔ after: POST http://localhost:8800/admin/fault · HTTP 200 · 0.0s · {"faq": "ok", "tickets": "ok", "prompts": "ok", "slow_seconds": 8.0} ✔ before: POST http://localhost:8800/admin/fault · HTTP 200 · 0.0s · {"faq": "ok", "tickets": "ok", "prompts": "error", "slow_seconds": 8.0} ✔ 저장소 고장 · 없는 릴리스는 그대로 400 · 0.0s ✔ after: POST http://localhost:8800/admin/fault · HTTP 200 · 0.0s · {"faq": "ok", "tickets": "ok", "prompts": "ok", "slow_seconds": 8.0} ✔ 운영(active 1.0.0)은 그대로 · 1.1s Passed 5/5 report: runs/lab02-challenge2-20261027-184235.json ✔ after: POST http://localhost:8800/admin/fault · HTTP 200 · 0.0s · {"faq": "ok", "tickets": "ok", "prompts": "ok", "slow_seconds": 8.0} ✔ after: POST http://localhost:8800/releases/helpdesk/reset · HTTP 200 · 0.0s · {"name": "helpdesk", "active": "1.0.0", "canary": null, "require_gate": false, "releases": {"1.0.0": {"prompt_version": $ uv run tools/flow.py release helpdesk --reset ✔ helpdesk: active 1.0.0 · no canary * 1.0.0 prompt p1 model gpt-4.1-mini 첫 릴리스 gate promote 9/9 1.1.0 prompt p2 model gpt-4.1-mini FAQ 답 끝에 출처 번호 gate promote 9/9 1.2.0 prompt p3 model gpt-4.1-mini 답을 한 문장으로 짧게 gate rollback 1/9 2.0.0 prompt p2 model gpt-5.4-nano 더 작은 모델 (비용) gate promote 9/9 2.1.0 prompt p9 model gpt-4.1-mini 출처 번호 · 존댓말 다듬기 (지시문 이름 확인 필요) gate rollback 0/9