fix(call2): plain text + woodworker tone

Review short/long must not show HTML tags; seed now requires plain text
only (newlines/- bullets) and practical woodworker copy. parse_call2_response
strips residual HTML as a safety net. Seed activation unchanged.
This commit is contained in:
grokbot_ty
2026-09-26 10:45:28 -07:00
parent c25e3f4927
commit 7e0157e45b
3 changed files with 120 additions and 48 deletions
+41 -16
View File
@@ -78,7 +78,7 @@ def test_call1_seed_is_locked_expert_prompt(env):
def test_call2_seed_has_short_long_structure(env):
"""Call 2 seed carries short+long structure and JSON dual output (not brand voice)."""
"""Call 2 seed: plain-text short+long, woodworker tone, JSON dual output (not brand voice)."""
client, _conn = env
from backend.inference import CALL2_SEED
@@ -86,13 +86,21 @@ def test_call2_seed_has_short_long_structure(env):
assert body["active_content"] == CALL2_SEED
assert "SHORT DESCRIPTION" in CALL2_SEED
assert "LONG DESCRIPTION" in CALL2_SEED
assert "Lead with the outcome" in CALL2_SEED
assert "PLAIN TEXT ONLY" in CALL2_SEED
assert "plain text only" in CALL2_SEED.lower()
assert "No HTML tags" in CALL2_SEED
assert "woodworkers choosing stock" in CALL2_SEED
assert "elevate" in CALL2_SEED # banned-phrase guidance
assert "stunning" in CALL2_SEED
assert "Lead with a practical outcome" in CALL2_SEED
assert "Hook" in CALL2_SEED
assert "Brand voice and Geography sections when provided" in CALL2_SEED
assert "Whidbey" not in CALL2_SEED
assert "Pacific Northwest" not in CALL2_SEED
assert '"short_description"' in CALL2_SEED
assert '"description"' in CALL2_SEED
assert "<HTML long description>" not in CALL2_SEED
assert "plain text long description" in CALL2_SEED
def test_taxonomy_lists_call1_closed_shape():
@@ -196,7 +204,7 @@ def test_call1_hard_disabled_410(env, monkeypatch):
def test_call2_stores_short_and_description(env, monkeypatch):
"""Call 2 persists both short_description and description from JSON output."""
"""Call 2 persists both fields as plain text (HTML from model is stripped)."""
client, conn = env
conn.execute("INSERT OR REPLACE INTO settings(key,value,value_enc) VALUES ('content_llm_enabled','true',NULL)")
conn.execute(
@@ -210,25 +218,29 @@ def test_call2_stores_short_and_description(env, monkeypatch):
import json as _json
payload = _json.dumps({
"short_description": "Turn a blank into a showpiece table — kiln-dried walnut with live edge character. Ready to finish.",
"description": "<p><strong>Showpiece ready.</strong></p><ul><li><strong>Stable:</strong> kiln dried</li></ul>",
"short_description": "Kiln-dried walnut live-edge stock for a dining table — clear midspan, usable width. Ready to finish.",
"description": "<p><strong>Dining table stock.</strong></p><ul><li><strong>Stable:</strong> kiln dried</li></ul>",
})
monkeypatch.setattr(InferenceClient, "chat", lambda self, messages: payload)
r = client.post("/api/v1/slabs/s1/inference/call2")
assert r.status_code == 200, r.text
body = r.json()
assert "Showpiece ready" in body["description"] or "kiln" in body["description"]
assert body["short_description"].startswith("Turn a blank")
assert "Dining table stock" in body["description"]
assert "kiln dried" in body["description"]
assert "<p>" not in body["description"]
assert "<strong>" not in body["description"]
assert body["short_description"].startswith("Kiln-dried walnut")
row = conn.execute(
"SELECT short_description, description, content_source FROM slabs WHERE id='s1'"
).fetchone()
assert row["short_description"].startswith("Turn a blank")
assert "<p>" in row["description"]
assert row["short_description"].startswith("Kiln-dried walnut")
assert "<p>" not in row["description"]
assert "- Stable:" in row["description"] or "Stable:" in row["description"]
assert row["content_source"] == "llm"
def test_call2_html_fallback_keeps_prior_short(env, monkeypatch):
"""Non-JSON Call 2 body becomes description only; prior short is left alone."""
"""Non-JSON Call 2 body becomes plain-text description; prior short is left alone."""
client, conn = env
conn.execute("INSERT OR REPLACE INTO settings(key,value,value_enc) VALUES ('content_llm_enabled','true',NULL)")
conn.execute(
@@ -243,32 +255,45 @@ def test_call2_html_fallback_keeps_prior_short(env, monkeypatch):
monkeypatch.setattr(InferenceClient, "chat", lambda self, messages: "<p>A fine walnut slab.</p>")
r = client.post("/api/v1/slabs/s1/inference/call2")
assert r.status_code == 200, r.text
assert r.json()["description"] == "<p>A fine walnut slab.</p>"
assert r.json()["description"] == "A fine walnut slab."
assert "short_description" not in r.json()
row = conn.execute(
"SELECT short_description, description, content_source FROM slabs WHERE id='s1'"
).fetchone()
assert row["short_description"] == "keep me"
assert row["description"] == "<p>A fine walnut slab.</p>"
assert row["description"] == "A fine walnut slab."
assert row["content_source"] == "llm"
def test_parse_call2_response_json_and_fenced():
from backend.inference import parse_call2_response
from backend.inference import parse_call2_response, _html_to_plain
import json as _json
short, desc = parse_call2_response(
_json.dumps({"short_description": " Benefit first. ", "description": " <p>Long</p> "})
)
assert short == "Benefit first."
assert desc == "<p>Long</p>"
assert desc == "Long"
fenced = "```json\n" + _json.dumps({"short_description": "S", "description": "<p>D</p>"}) + "\n```"
short2, desc2 = parse_call2_response(fenced)
assert short2 == "S"
assert desc2 == "<p>D</p>"
assert desc2 == "D"
short3, desc3 = parse_call2_response("<p>only long</p>")
assert short3 is None
assert desc3 == "<p>only long</p>"
assert desc3 == "only long"
# Defensive strip: lists become "- " bullets; entities unescaped; no tags left.
plain = _html_to_plain(
"<p>Hook.</p><ul><li><strong>Stable:</strong> kiln dried</li>"
"<li>Live edge</li></ul><p>Trust &amp; ship.</p>"
)
assert "<" not in plain
assert "Hook." in plain
assert "- Stable: kiln dried" in plain
assert "- Live edge" in plain
assert "Trust & ship." in plain
# Already-plain text is unchanged aside from trim.
assert _html_to_plain(" Kiln-dried walnut for a bar top. ") == "Kiln-dried walnut for a bar top."
def test_call1_disabled_even_when_inference_off(env):