fix(vision): NaN/inf/bool di uno strumento non diventano più una quota (#16)

runner.run_graph esclude bool e NaN/inf dagli output numerici, con il
motivo in RunOutcome.invalid_outputs. vision_service tratta una quota
mappata con valore None/assente/non finito come "non prodotta" (422),
invece di arrivare a float(None) e sollevare TypeError.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-21 22:35:53 +02:00
parent 10261b66f0
commit 20957e517d
5 changed files with 137 additions and 4 deletions
+44
View File
@@ -159,6 +159,50 @@ async def test_a_missing_output_names_itself(
assert (await db_session.execute(select(Measurement))).scalars().all() == []
@pytest.mark.asyncio
async def test_a_null_output_counts_as_not_produced(
client, db_session, measurement_tec_user, worker_says,
):
"""A worker answering with the key present but null (not omitted) must not
reach float(None) as a bare TypeError - it is "not produced", same as a
missing key (#16)."""
recipe = await create_test_recipe(db_session, measurement_tec_user.id)
version, task, first, second = await two_vision_quotes(db_session, recipe.id)
worker_says({"t1.diameter": None, "t1.radius": GOOD})
response = await client.post(
"/api/vision/execute",
headers=auth_headers(measurement_tec_user),
files={"image": ("p.png", an_image(), "image/png")},
data={"task_id": str(task.id)},
)
assert response.status_code == 422
assert "t1.diameter" in response.json()["detail"]
assert (await db_session.execute(select(Measurement))).scalars().all() == []
@pytest.mark.asyncio
async def test_a_non_finite_output_counts_as_not_produced(
client, db_session, measurement_tec_user, worker_says,
):
"""NaN/inf must not become a saved measurement (#16)."""
recipe = await create_test_recipe(db_session, measurement_tec_user.id)
version, task, first, second = await two_vision_quotes(db_session, recipe.id)
worker_says({"t1.diameter": float("nan"), "t1.radius": GOOD})
response = await client.post(
"/api/vision/execute",
headers=auth_headers(measurement_tec_user),
files={"image": ("p.png", an_image(), "image/png")},
data={"task_id": str(task.id)},
)
assert response.status_code == 422
assert "t1.diameter" in response.json()["detail"]
assert (await db_session.execute(select(Measurement))).scalars().all() == []
@pytest.mark.asyncio
async def test_a_task_without_a_graph_is_refused(
client, db_session, measurement_tec_user, worker_says,