fix(review): slug-scoped tags, decode names, drop fig picker & AI labels

- Taxonomy sync keeps fig-/feat- by slug (hyphen), not name; HTML-unescape names
- Review: remove AI assist labels; Features picker for feat-*; derive fig_tag_ids
  from Figure term names (casefold match, no bridges); decodeName on display
- Unit tests for scoped_tags, fig match, Review UI contract; docs slug wording
This commit is contained in:
grokbot_ty
2026-09-26 09:41:30 -07:00
parent c54870f5b9
commit 85786f16f2
13 changed files with 214 additions and 85 deletions
+25 -7
View File
@@ -1,11 +1,14 @@
"""Taxonomy sync: pull Woo categories/tags/attributes/terms into the local cache.
Rebuild happens in one transaction; on any failure the prior cache is kept.
Only fig-* / feat-* tag families are retained (METADATA-15). taxonomy_anchor is a
stable hash of the stored subset, recorded only when it changes.
Only fig-* / feat-* tag families are retained by **slug** prefix with hyphen
(SETTINGS-51 / METADATA-15). taxonomy_anchor is a stable hash of the stored
subset, recorded only when it changes. Display names are HTML-unescaped so
Woo entities like ``&`` store as ``&``.
"""
import hashlib
import html
import json
from datetime import datetime, timezone
@@ -16,8 +19,23 @@ def _now_iso() -> str:
return datetime.now(timezone.utc).replace(microsecond=0, tzinfo=None).isoformat()
def _decode_name(name: str | None) -> str:
"""Decode HTML entities Woo puts in taxonomy display names."""
return html.unescape(name or "")
def _scoped_tags(tags: list[dict]) -> list[dict]:
return [t for t in tags if t.get("name", "").startswith(("fig-", "feat-"))]
"""Keep product tags whose slug starts with fig- or feat- (hyphen required).
Live Woo uses human display names (e.g. "Curl") with slugs like fig-curl.
Filtering by name prefix kept 0 live tags; slug is authoritative.
"""
out = []
for t in tags:
slug = t.get("slug") or ""
if slug.startswith("fig-") or slug.startswith("feat-"):
out.append(t)
return out
def _normalize_category(c: dict) -> tuple:
@@ -34,7 +52,7 @@ def _normalize_category(c: dict) -> tuple:
woo_id = c.get("woo_id", c.get("id"))
if woo_id is not None:
woo_id = int(woo_id)
return (c["id"], c["name"], c["slug"], parent_id, woo_id)
return (c["id"], _decode_name(c["name"]), c["slug"], parent_id, woo_id)
def _subset_hash(categories: list[dict], attributes: list[dict],
@@ -90,16 +108,16 @@ def sync(client: WooClient, conn) -> dict:
conn.executemany(
"INSERT INTO woo_attributes(id, name, slug, woo_id) VALUES (?,?,?,?)",
[(a["id"], a["name"], a["slug"], a.get("woo_id")) for a in attributes],
[(a["id"], _decode_name(a["name"]), a["slug"], a.get("woo_id")) for a in attributes],
)
for attr_id, terms in terms_by_attr.items():
conn.executemany(
"INSERT INTO woo_attribute_terms(id, attribute_id, name, slug, woo_id) VALUES (?,?,?,?,?)",
[(t["id"], attr_id, t["name"], t["slug"], t.get("woo_id")) for t in terms],
[(t["id"], attr_id, _decode_name(t["name"]), t["slug"], t.get("woo_id")) for t in terms],
)
conn.executemany(
"INSERT INTO woo_tags(id, name, slug, woo_id) VALUES (?,?,?,?)",
[(t["id"], t["name"], t["slug"], t.get("woo_id")) for t in scoped_tags],
[(t["id"], _decode_name(t["name"]), t["slug"], t.get("woo_id")) for t in scoped_tags],
)
anchor = _subset_hash(categories, attributes, terms_by_attr, scoped_tags)