feat(wordpress): only assign tags that are established
_resolve_wp_tag_ids created a WordPress tag for every keyword the rewriter invented, up to 12 per post. That is where the 3.055 tags for 955 posts came from - 1.683 of them used exactly once, 473 attached to no post at all. The categories are stable now, but the tags would simply grow back. Three changes, all on the write path: A proposed tag has to appear for wordpress_new_tag_min_proposals (3) different articles before it is created. Proposals are counted in the new tag_proposals table, keyed on (name, article), so re-publishing an article does not inflate its own count. Tags that already exist in WordPress are assigned as before - the gate only guards creation. Only the first wordpress_max_tags_per_post (5) tags reach WordPress. The full list still feeds the category rules, which were validated against it. The lookup fallback of reusing the first search hit is gone. It filed "Camping" under the unrelated existing tag "Campingplatz" whenever the exact tag was missing, which quietly produced wrong tags rather than none. If the proposal bookkeeping fails, nothing is creatable that run: existing tags still get assigned and the taxonomy stays put, rather than falling back to creating everything. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
4282759b2c
commit
682755c6a0
5 changed files with 266 additions and 15 deletions
|
|
@ -853,3 +853,41 @@ def list_articles(limit: int = 100, status_filter: str | None = None) -> list[di
|
|||
(safe_limit,),
|
||||
).fetchall()
|
||||
return rows_to_dicts(rows)
|
||||
|
||||
|
||||
def record_tag_proposals(names: list[str], article_id: int | None) -> dict[str, int]:
|
||||
"""Record that these tags were proposed for one article.
|
||||
|
||||
Returns, per casefolded name, how many distinct articles have proposed it so
|
||||
far - this one included. That count is what decides whether a tag is
|
||||
established enough to be created in WordPress: a tag the rewriter invents
|
||||
once for a single article should not become a permanent taxonomy entry.
|
||||
|
||||
Re-publishing an article does not inflate the count, because the row is
|
||||
keyed on (name_key, article_id). Articles without an id (ad-hoc publishing)
|
||||
all share the sentinel 0 and therefore count once in total.
|
||||
"""
|
||||
counts: dict[str, int] = {}
|
||||
if not names:
|
||||
return counts
|
||||
key_for_article = int(article_id or 0)
|
||||
with get_conn() as conn:
|
||||
for raw in names:
|
||||
name = str(raw or "").strip()
|
||||
if not name:
|
||||
continue
|
||||
name_key = name.casefold()
|
||||
conn.execute(
|
||||
"""
|
||||
INSERT INTO tag_proposals (name_key, name, article_id)
|
||||
VALUES (?, ?, ?)
|
||||
ON CONFLICT(name_key, article_id) DO NOTHING
|
||||
""",
|
||||
(name_key, name, key_for_article),
|
||||
)
|
||||
row = conn.execute(
|
||||
"SELECT COUNT(*) AS n FROM tag_proposals WHERE name_key = ?",
|
||||
(name_key,),
|
||||
).fetchone()
|
||||
counts[name_key] = int(row["n"] if row else 0)
|
||||
return counts
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue