chore(inference): disable Call 1 end-to-end; Call 2 stays
overnight-whole-app: Call 1 (vision classification) is OUT.
- POST /api/v1/slabs/{id}/inference/call1 always returns 410 call1_disabled
(no model chat, no inference_log). Prompt seed/revision APIs kept dormant.
- Review: remove "Suggest with AI" / runInference (inferTaxon).
- GenerateText: remove Classify metadata (Call 1) button; Call 2 generate stays.
- PROMPTS.md banner documents Call 1 OUT / Call 2 STAYS.
- Settings: inference_enabled toggle annotated as Call-1 latch (dormant).
- Backend tests updated to assert 410; Call 2 tests unchanged.
This commit is contained in:
@@ -153,42 +153,28 @@ def test_gate_feature_tag_ids_not_free_text():
|
||||
assert "feature_tag_ids" not in _gate(low)
|
||||
|
||||
|
||||
def test_call1_confidence_gate(env, monkeypatch):
|
||||
def test_call1_hard_disabled_410(env, monkeypatch):
|
||||
"""overnight-whole-app: Call 1 OUT — POST always 410, never chats the model."""
|
||||
client, conn = env
|
||||
# enable inference
|
||||
conn.execute("INSERT OR REPLACE INTO settings(key,value,value_enc) VALUES ('inference_enabled','true',NULL)")
|
||||
conn.execute("INSERT INTO woo_categories(id,name,slug,parent_id,woo_id) VALUES (1,'Black Walnut','black-walnut',NULL,100)")
|
||||
conn.execute("INSERT INTO slabs(id,sku,length_in,thickness_in,status,server_rev,client_rev,created_at,updated_at) VALUES ('s1','SLAB-01',100,2,'calibrated',1,1,'t','t')")
|
||||
conn.execute("INSERT INTO slab_photos(id,slab_id,seq,processed_blob,created_at) VALUES ('p1','s1',1,X'89504E47','t')")
|
||||
conn.commit()
|
||||
from backend.inference import InferenceClient
|
||||
|
||||
called = {"n": 0}
|
||||
|
||||
def fake_chat(self, messages):
|
||||
# Capture list header for #86 shape
|
||||
text = messages[0]["content"][-1]["text"]
|
||||
assert "LISTS:" in text
|
||||
assert "grade_terms" not in text
|
||||
assert "species_leaves" not in text
|
||||
return json.dumps({
|
||||
"species_id": 1, "species_confidence": 0.9,
|
||||
"wood_category_ids": [1], "wood_category_confidence": 0.5, # below threshold
|
||||
"grade_term_id": 7, "grade_confidence": 0.99, # never suggested
|
||||
"figure_term_ids": [2], "figure_confidence": 0.8, # at/above
|
||||
"feature_tag_ids": [9], "feature_tag_confidence": 0.9,
|
||||
"character": ["x"], "inclusions": ["y"],
|
||||
})
|
||||
called["n"] += 1
|
||||
return "{}"
|
||||
|
||||
monkeypatch.setattr(InferenceClient, "chat", fake_chat)
|
||||
r = client.post("/api/v1/slabs/s1/inference/call1")
|
||||
assert r.status_code == 200, r.text
|
||||
s = r.json()["suggestions"]
|
||||
assert s.get("species_id") == 1
|
||||
assert s.get("figure_term_ids") == [2]
|
||||
assert s.get("feature_tag_ids") == [9]
|
||||
assert "wood_category_ids" not in s # gated out
|
||||
assert "grade_term_id" not in s # never
|
||||
assert "character" not in s
|
||||
# inference_log written with call=1
|
||||
assert conn.execute("SELECT call FROM inference_log").fetchone()["call"] == 1
|
||||
assert r.status_code == 410, r.text
|
||||
body = r.json()
|
||||
assert body["error"]["code"] == "call1_disabled"
|
||||
assert called["n"] == 0
|
||||
assert conn.execute("SELECT COUNT(*) AS n FROM inference_log").fetchone()["n"] == 0
|
||||
|
||||
|
||||
def test_call2_stores_description(env, monkeypatch):
|
||||
@@ -208,12 +194,14 @@ def test_call2_stores_description(env, monkeypatch):
|
||||
assert row["content_source"] == "llm"
|
||||
|
||||
|
||||
def test_inference_off_call1_409(env):
|
||||
def test_call1_disabled_even_when_inference_off(env):
|
||||
"""Call 1 hard-disable wins over inference_enabled=false (still 410, not 409)."""
|
||||
client, conn = env
|
||||
conn.execute("INSERT INTO slabs(id,sku,status,server_rev,client_rev,created_at,updated_at) VALUES ('s1','SLAB-01','calibrated',1,1,'t','t')")
|
||||
conn.commit()
|
||||
r = client.post("/api/v1/slabs/s1/inference/call1")
|
||||
assert r.status_code == 409 # inference_enabled default off
|
||||
assert r.status_code == 410
|
||||
assert r.json()["error"]["code"] == "call1_disabled"
|
||||
|
||||
|
||||
def test_server_description_inference_off(env):
|
||||
@@ -306,50 +294,18 @@ def test_redact_request_for_log_strips_data_urls_keeps_text():
|
||||
assert "LISTS:" in parts[2]["text"]
|
||||
|
||||
|
||||
def test_call1_log_has_text_and_image_refs_no_base64(env, monkeypatch):
|
||||
"""#87 METADATA-66: inference_log stores text+refs, not image bytes."""
|
||||
def test_call1_log_skipped_while_disabled(env):
|
||||
"""#87 Call 1 log path dormant while Call 1 is hard-disabled (overnight-whole-app)."""
|
||||
client, conn = env
|
||||
conn.execute("INSERT OR REPLACE INTO settings(key,value,value_enc) VALUES ('inference_enabled','true',NULL)")
|
||||
conn.execute(
|
||||
"INSERT INTO slabs(id,sku,length_in,thickness_in,status,server_rev,client_rev,created_at,updated_at) "
|
||||
"VALUES ('s1','SLAB-01',100,2,'calibrated',1,1,'t','t')"
|
||||
)
|
||||
png = _rgba_png(400, 300)
|
||||
conn.execute(
|
||||
"INSERT INTO slab_photos(id,slab_id,seq,processed_blob,created_at) VALUES ('photo-abc','s1',1,?, 't')",
|
||||
(png,),
|
||||
)
|
||||
conn.commit()
|
||||
from backend.inference import InferenceClient
|
||||
|
||||
def fake_chat(self, messages):
|
||||
# Wire path still has data-URL for the model
|
||||
content = messages[0]["content"]
|
||||
assert any(
|
||||
isinstance(p, dict) and p.get("type") == "image_url"
|
||||
and str(p.get("image_url", {}).get("url", "")).startswith("data:image")
|
||||
for p in content
|
||||
)
|
||||
return json.dumps({"species_id": 1, "species_confidence": 0.9})
|
||||
|
||||
monkeypatch.setattr(InferenceClient, "chat", fake_chat)
|
||||
r = client.post("/api/v1/slabs/s1/inference/call1")
|
||||
assert r.status_code == 200, r.text
|
||||
row = conn.execute(
|
||||
"SELECT request_payload, length(request_payload) AS n FROM inference_log ORDER BY id DESC LIMIT 1"
|
||||
).fetchone()
|
||||
payload = row["request_payload"]
|
||||
assert row["n"] < 50000
|
||||
assert "data:image" not in payload
|
||||
assert "LISTS:" in payload
|
||||
assert "image_ref" in payload
|
||||
assert "photo-abc" in payload
|
||||
assert '"seq": 1' in payload or '"seq":1' in payload
|
||||
logged = json.loads(payload)
|
||||
refs = [p for p in logged[0]["content"] if p.get("type") == "image_ref"]
|
||||
assert len(refs) == 1
|
||||
assert refs[0]["photo_id"] == "photo-abc"
|
||||
assert refs[0]["bytes"] == len(png)
|
||||
assert r.status_code == 410
|
||||
assert conn.execute("SELECT COUNT(*) AS n FROM inference_log").fetchone()["n"] == 0
|
||||
|
||||
|
||||
def test_call2_log_redacts_images(env, monkeypatch):
|
||||
@@ -380,38 +336,9 @@ def test_call2_log_redacts_images(env, monkeypatch):
|
||||
assert "DIMENSION FACT BLOCK" in payload
|
||||
|
||||
|
||||
def test_call1_sends_long_edge_at_most_1024(env, monkeypatch):
|
||||
"""METADATA-35 end-to-end: messages to the model use <=1024 long edge."""
|
||||
client, conn = env
|
||||
conn.execute("INSERT OR REPLACE INTO settings(key,value,value_enc) VALUES ('inference_enabled','true',NULL)")
|
||||
conn.execute(
|
||||
"INSERT INTO slabs(id,sku,length_in,thickness_in,status,server_rev,client_rev,created_at,updated_at) "
|
||||
"VALUES ('s1','SLAB-01',100,2,'calibrated',1,1,'t','t')"
|
||||
)
|
||||
big = _rgba_png(800, 1067)
|
||||
conn.execute(
|
||||
"INSERT INTO slab_photos(id,slab_id,seq,processed_blob,created_at) VALUES ('p1','s1',1,?, 't')",
|
||||
(big,),
|
||||
)
|
||||
conn.commit()
|
||||
from backend.inference import InferenceClient
|
||||
from PIL import Image
|
||||
import io
|
||||
|
||||
captured = {}
|
||||
|
||||
def fake_chat(self, messages):
|
||||
captured["messages"] = messages
|
||||
return json.dumps({"species_id": 1, "species_confidence": 0.9})
|
||||
|
||||
monkeypatch.setattr(InferenceClient, "chat", fake_chat)
|
||||
r = client.post("/api/v1/slabs/s1/inference/call1")
|
||||
assert r.status_code == 200, r.text
|
||||
content = captured["messages"][0]["content"]
|
||||
imgs = [p for p in content if isinstance(p, dict) and p.get("type") == "image_url"]
|
||||
assert len(imgs) == 1
|
||||
url = imgs[0]["image_url"]["url"]
|
||||
assert url.startswith("data:image/png;base64,")
|
||||
raw = base64.b64decode(url.split(",", 1)[1])
|
||||
im = Image.open(io.BytesIO(raw))
|
||||
assert max(im.size) <= 1024
|
||||
def test_call1_sends_long_edge_dormant_while_disabled(env):
|
||||
"""METADATA-35 Call 1 sizing path dormant while Call 1 is hard-disabled."""
|
||||
client, _conn = env
|
||||
r = client.post("/api/v1/slabs/missing/inference/call1")
|
||||
assert r.status_code == 410
|
||||
assert r.json()["error"]["code"] == "call1_disabled"
|
||||
|
||||
Reference in New Issue
Block a user