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>
28 lines
662 B
Python
28 lines
662 B
Python
"""Domain and MetricBound dataclasses."""
|
||
|
||
from __future__ import annotations
|
||
|
||
from dataclasses import dataclass, field
|
||
|
||
|
||
@dataclass
|
||
class MetricBound:
|
||
"""Per-metric weight and normalization bounds within a domain."""
|
||
|
||
metric_name: str
|
||
weight: float # 0.0–1.0
|
||
norm_min: float # Below this → score 0
|
||
norm_max: float # Above this → score 1
|
||
unit: str = ""
|
||
metric_id: int | None = None
|
||
|
||
|
||
@dataclass
|
||
class Domain:
|
||
"""A context frame that defines what 'good' means (e.g., urban_commuting)."""
|
||
|
||
name: str
|
||
description: str = ""
|
||
metric_bounds: list[MetricBound] = field(default_factory=list)
|
||
id: int | None = None
|