Add async pipeline with progress monitoring, resumability, and result transparency
Pipeline engine rewritten with combo-first loop: each combination is processed through all requested passes before moving to the next, with incremental DB saves after every step (crash-safe). Blocked combos now get result rows so they appear in the results page with constraint violation reasons. New pipeline_runs table tracks run lifecycle (pending/running/completed/failed/ cancelled). Web route launches pipeline in a background thread with its own DB connection. HTMX polling partial shows live progress with per-pass breakdown. Also: status guard prevents reviewed->scored downgrade, save_combination loads existing status on dedup for correct resume, per-metric scores show domain bounds + units + position bars, ensure_metric backfills units on existing rows. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -154,3 +154,77 @@ dd { font-size: 0.9rem; }
|
||||
|
||||
/* ── Dep add form ────────────────────────────────────────── */
|
||||
.dep-add-form { margin-top: 0.75rem; }
|
||||
|
||||
/* ── Form hints ──────────────────────────────────────────── */
|
||||
.form-hint { color: #666; font-size: 0.8rem; margin-bottom: 0.25rem; font-weight: 400; }
|
||||
|
||||
/* ── Vertical checkbox list ──────────────────────────────── */
|
||||
.checkbox-col { display: flex; flex-direction: column; gap: 0.5rem; }
|
||||
.checkbox-col label { display: flex; align-items: baseline; gap: 0.4rem; font-size: 0.9rem; }
|
||||
.checkbox-col label .form-hint { display: block; margin-left: 1.3rem; }
|
||||
|
||||
/* ── Summary DL (pipeline) ───────────────────────────────── */
|
||||
.summary-dl { display: grid; grid-template-columns: auto 1fr; gap: 0.15rem 1rem; }
|
||||
|
||||
/* ── Pipeline run status ────────────────────────────────── */
|
||||
.badge-running { background: #dbeafe; color: #1e40af; }
|
||||
.badge-completed { background: #dcfce7; color: #166534; }
|
||||
.badge-failed { background: #fee2e2; color: #991b1b; }
|
||||
.badge-cancelled { background: #fef3c7; color: #92400e; }
|
||||
|
||||
.run-status { padding: 0.25rem 0; }
|
||||
.run-status-header { display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.5rem; }
|
||||
.run-status-label { font-weight: 600; font-size: 0.9rem; }
|
||||
|
||||
.progress-bar-container {
|
||||
background: #e5e7eb;
|
||||
border-radius: 4px;
|
||||
height: 8px;
|
||||
overflow: hidden;
|
||||
margin-bottom: 0.35rem;
|
||||
}
|
||||
.progress-bar {
|
||||
background: #2563eb;
|
||||
height: 100%;
|
||||
border-radius: 4px;
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
|
||||
.run-status-counters {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
font-size: 0.8rem;
|
||||
color: #555;
|
||||
margin-bottom: 0.35rem;
|
||||
}
|
||||
|
||||
.run-status-actions { margin-top: 0.35rem; }
|
||||
|
||||
/* ── Block reason ───────────────────────────────────────── */
|
||||
.block-reason-cell {
|
||||
font-size: 0.8rem;
|
||||
color: #666;
|
||||
max-width: 350px;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
/* ── Metric position bar ────────────────────────────────── */
|
||||
.metric-bar-container {
|
||||
display: inline-block;
|
||||
width: 60px;
|
||||
height: 6px;
|
||||
background: #e5e7eb;
|
||||
border-radius: 3px;
|
||||
overflow: hidden;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.metric-bar {
|
||||
height: 100%;
|
||||
background: #2563eb;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.metric-bar-label {
|
||||
font-size: 0.75rem;
|
||||
color: #666;
|
||||
margin-left: 0.3rem;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user