Monitor: quota con soli NaN resta in elenco con media null e fuori tolleranza
Refs #118 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -12,7 +12,7 @@ class MonitorSubtask(BaseModel):
|
|||||||
description: str
|
description: str
|
||||||
unit: str
|
unit: str
|
||||||
count: int
|
count: int
|
||||||
mean: float
|
mean: Optional[float] = None # #118: None = solo quote NaN
|
||||||
ltl: Optional[float] = None
|
ltl: Optional[float] = None
|
||||||
utl: Optional[float] = None
|
utl: Optional[float] = None
|
||||||
# True when ltl <= mean <= utl (a missing limit does not constrain).
|
# True when ltl <= mean <= utl (a missing limit does not constrain).
|
||||||
|
|||||||
@@ -96,19 +96,21 @@ async def list_open_runs(db: AsyncSession) -> list[MonitorRun]:
|
|||||||
per_sub[row.subtask_id].append(row)
|
per_sub[row.subtask_id].append(row)
|
||||||
subtasks = []
|
subtasks = []
|
||||||
for sid, group in sorted(per_sub.items()):
|
for sid, group in sorted(per_sub.items()):
|
||||||
# #118: le quote NaN (value None) non entrano nella media; senza
|
# #118: le quote NaN (value None) non entrano nella media; con soli
|
||||||
# nessun valore numerico la quota non ha una media da mostrare
|
# NaN la quota resta in elenco con mean None ed e' fuori tolleranza
|
||||||
numeric = [float(g.value) for g in group if g.value is not None]
|
numeric = [float(g.value) for g in group if g.value is not None]
|
||||||
if not numeric:
|
mean = sum(numeric) / len(numeric) if numeric else None
|
||||||
continue
|
|
||||||
mean = sum(numeric) / len(numeric)
|
|
||||||
first = group[0]
|
first = group[0]
|
||||||
subtasks.append(MonitorSubtask(
|
subtasks.append(MonitorSubtask(
|
||||||
subtask_id=sid, description=first.description, unit=first.unit,
|
subtask_id=sid, description=first.description, unit=first.unit,
|
||||||
count=len(group), mean=round(mean, 6),
|
count=len(group),
|
||||||
|
mean=round(mean, 6) if mean is not None else None, # #118
|
||||||
ltl=float(first.ltl) if first.ltl is not None else None,
|
ltl=float(first.ltl) if first.ltl is not None else None,
|
||||||
utl=float(first.utl) if first.utl is not None else None,
|
utl=float(first.utl) if first.utl is not None else None,
|
||||||
in_tolerance=_in_tolerance(mean, first.ltl, first.utl),
|
in_tolerance=(
|
||||||
|
_in_tolerance(mean, first.ltl, first.utl)
|
||||||
|
if mean is not None else False # #118: tutte NaN = fail
|
||||||
|
),
|
||||||
))
|
))
|
||||||
timer = production_service.describe(run)
|
timer = production_service.describe(run)
|
||||||
ev = last_event.get(run.id)
|
ev = last_event.get(run.id)
|
||||||
|
|||||||
@@ -81,3 +81,29 @@ async def test_open_lists_only_open_runs_with_means(client, db_session, admin_us
|
|||||||
async def test_open_empty_for_admin(client, admin_user):
|
async def test_open_empty_for_admin(client, admin_user):
|
||||||
resp = await client.get("/api/production-runs/open", headers=auth_headers(admin_user))
|
resp = await client.get("/api/production-runs/open", headers=auth_headers(admin_user))
|
||||||
assert resp.status_code == 200 and resp.json() == []
|
assert resp.status_code == 200 and resp.json() == []
|
||||||
|
|
||||||
|
|
||||||
|
async def test_nan_quotes_in_the_monitor(client, db_session, admin_user):
|
||||||
|
"""#118: solo NaN -> la quota resta, mean null e fuori tolleranza; mista -> media dei numeri."""
|
||||||
|
sup = await _create_user(db_session, "capo", roles=["Supervisor"])
|
||||||
|
r1, s1, v1 = await _run(db_session, admin_user, "N1")
|
||||||
|
r2, s2, v2 = await _run(db_session, admin_user, "N2")
|
||||||
|
for i in range(2):
|
||||||
|
db_session.add(_m(r1, s1, v1, admin_user, None, "fail", i))
|
||||||
|
for i, (val, pf) in enumerate([(None, "fail"), (10.0, "pass"), (10.2, "pass")]):
|
||||||
|
db_session.add(_m(r2, s2, v2, admin_user, val, pf, i))
|
||||||
|
await db_session.commit()
|
||||||
|
|
||||||
|
resp = await client.get("/api/production-runs/open", headers=auth_headers(sup))
|
||||||
|
assert resp.status_code == 200
|
||||||
|
body = {r["station_code"]: r for r in resp.json()}
|
||||||
|
only_nan = body["ST-N1"]["subtasks"]
|
||||||
|
assert len(only_nan) == 1
|
||||||
|
assert only_nan[0]["mean"] is None
|
||||||
|
assert only_nan[0]["count"] == 2
|
||||||
|
assert only_nan[0]["in_tolerance"] is False
|
||||||
|
assert body["ST-N1"]["fail_count"] == 2
|
||||||
|
mixed = body["ST-N2"]["subtasks"][0]
|
||||||
|
assert mixed["count"] == 3
|
||||||
|
assert round(mixed["mean"], 6) == 10.1
|
||||||
|
assert mixed["in_tolerance"] is True
|
||||||
|
|||||||
Reference in New Issue
Block a user