fix(review): Create title no silent fail; gate enables content LLM

Create title used to look enabled while review echoed a pre-typed title when
species/primary were missing from taxonomy (no error). Persist wood cats before
the deterministic build, return title_built / title_build_missing from review,
and surface a Create-title nudge like Create desc.

WooSetupGate now turns on content_llm_enabled when inference URL+key are set
(Call 2 / Create desc). Call 1 stays out. Create-desc gate also requires
inference URL+key so empty Settings show a clear missing list.
This commit is contained in:
grokbot_ty
2026-09-26 22:50:15 -07:00
parent f54cc37dcc
commit fca32396c0
10 changed files with 187 additions and 19 deletions
+27 -6
View File
@@ -184,12 +184,23 @@ async def review_slab(slab_id: str, payload: dict[str, Any] | None = None) -> di
# they are produced by the deterministic build below, not persisted from the
# payload (so the review POST can't clobber the owner's Create workflow).
cats, terms = _taxonomy_lookup(conn)
primary_id = payload.get("primary_wood_category_id")
def _as_cat_id(v):
if v is None or v == "":
return None
try:
return int(v)
except (TypeError, ValueError):
return None
primary_id = _as_cat_id(payload.get("primary_wood_category_id"))
wood_cats = slab.get("wood_category_ids") or []
if not primary_id:
primary_id = wood_cats[0] if wood_cats else None
primary_leaf = cats.get(primary_id, {}) if primary_id else {}
species_name = cats.get(slab.get("species_id"), {}).get("name", "") if slab.get("species_id") else ""
primary_id = _as_cat_id(wood_cats[0]) if wood_cats else None
# Taxonomy rows use integer PKs; coerce so string JSON ids still resolve.
primary_leaf = cats.get(primary_id, {}) if primary_id is not None else {}
species_id = _as_cat_id(slab.get("species_id"))
species_name = cats.get(species_id, {}).get("name", "") if species_id is not None else ""
figure_term_ids = slab.get("figure_term_ids") or []
figure = terms.get(figure_term_ids[0], {}).get("name") if figure_term_ids else None
@@ -210,14 +221,22 @@ async def review_slab(slab_id: str, payload: dict[str, Any] | None = None) -> di
# Deterministic title / short_description, re-derived from the current
# metadata on every review (the Create button's source of truth).
# #98: pass synced terms so Live Edge comes from the edge term, not any id.
# title_built tells the client whether the Create-title path actually ran
# (vs echoing a pre-typed title when species/primary are missing from taxonomy).
title_build_missing: list[str] = []
if not species_name:
title_build_missing.append("species")
if not primary_leaf:
title_build_missing.append("primary_wood_category")
title_built = not title_build_missing
title = (
build_title(slab, figure, species_name, primary_leaf, terms)
if (primary_leaf and species_name)
if title_built
else slab.get("title") or None
)
short_desc = (
build_short_description(slab, figure, species_name, primary_leaf, terms)
if (primary_leaf and species_name)
if title_built
else slab.get("short_description") or None
)
@@ -227,6 +246,8 @@ async def review_slab(slab_id: str, payload: dict[str, Any] | None = None) -> di
"ready": ready, "missing": missing, "title": title, "short_description": short_desc,
"price": price, "price_suggestion": price_suggestion(conn, slab),
"primary_wood_category_id": primary_id,
"title_built": title_built,
"title_build_missing": title_build_missing,
}
+24
View File
@@ -62,6 +62,8 @@ def test_title_live_edge_no_dims(env):
body = r.json()
assert body["title"] == "Figured Black Walnut Live Edge Slab"
assert body["short_description"].startswith("Figured Black Walnut Live Edge Slab, 9ft 6in x 24.3in x 1.75in")
assert body["title_built"] is True
assert body["title_build_missing"] == []
assert "18.4 bdft" in body["short_description"]
@@ -220,3 +222,25 @@ def test_ready_requires_figure_term_ids(env):
})
# May still miss other fields depending on fixture; figure must not be listed
assert "figure_term_ids" not in missing2
def test_review_title_built_false_without_species_or_primary(env):
"""Create-title silent-fail fix: report title_built=false when taxonomy cannot resolve."""
client, conn = env
conn.execute(
"INSERT INTO slabs(id,sku,length_in,thickness_in,sqft,bdft,width_min_in,width_max_in,width_avg_in,"
"species_id,wood_category_ids,figure_term_ids,price,price_source,title,short_description,description,"
"content_source,status,server_rev,client_rev,created_at,updated_at) "
"VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
("s1", None, 114.0, 1.75, 30.0, 18.4, 18.0, 24.3, 24.3, None, "[]", "[]", None, None,
"Typed Title", None, None, "manual", "calibrated", 1, 1, "t", "t"),
)
conn.commit()
r = client.post("/api/v1/slabs/s1/review", json={})
assert r.status_code == 200, r.text
body = r.json()
assert body["title_built"] is False
assert "species" in body["title_build_missing"]
assert "primary_wood_category" in body["title_build_missing"]
assert body["title"] == "Typed Title"
assert body["short_description"] is None