feat(board): 처리 보드 v2 — 파이프라인 흐름 뷰·엔진 구분·실패 재시도/건너뛰기 (ds-board-engines-1)

- 흐름 뷰 메인: 좌→우 노드(머신·엔진 태그, 유입 우세 amber, 실패 뱃지) + 머신 스트립(모델 표기) + trend_24h 스파크라인 첫 렌더
- 노드 클릭 상세 패널: KV 4칸 + 다중 stage 행 + 지금 처리 중
- 실패 처리 드로어: 에러 패턴 그룹 + 재시도/건너뛰기 (영구 실패의 첫 사용자 조치 경로)
- API: stages[].done_1h/created_1h 노출 + GET /api/queue/failed + POST /api/queue/retry|/skip (uq_queue_active 충돌 skip, 건너뛰기는 enqueue_next_stage 미호출)
- 엔진/모델 표기 = queueDisplay.ts 정적 맵 단일 지점 (모델 교체 시 1곳)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
hyungi
2026-06-12 01:05:04 +00:00
parent 8ac1dbf4a8
commit 5581d3f1ce
7 changed files with 744 additions and 71 deletions
+11 -2
View File
@@ -379,5 +379,14 @@ def test_build_stages_order_fields_and_age():
assert by["extract"]["failed"] == 2
assert by["extract"]["oldest_pending_age_sec"] is None
# 전 stage 행 존재 (빈 단계 숨김은 FE 몫)
assert {"stage", "pending", "processing", "failed", "done_today",
"oldest_pending_age_sec"} == set(rows[0].keys())
assert {"stage", "pending", "processing", "failed", "done_1h", "created_1h",
"done_today", "oldest_pending_age_sec"} == set(rows[0].keys())
def test_build_stages_exposes_rates():
"""ds-board-engines-1: done_1h/created_1h 노출 — 흐름 노드 처리율·ETA·유입 우세 재료."""
from services.queue_overview import build_stages
stats = {"embed": _stage(pending=4, done_1h=600, created_1h=120, done_today=900)}
rows = build_stages(stats)
embed = next(r for r in rows if r["stage"] == "embed")
assert (embed["done_1h"], embed["created_1h"], embed["done_today"]) == (600, 120, 900)