""" Reusable SEO rule engine for The Exclusion Zone (EN) — theexclusionzone.com (Ghost). Pure functions, NO I/O. Feed it a Ghost Admin API post dict (with `html` format included) and it returns a list of Violation(rule, severity, message, fix). Shared by: - seo_audit.py — Tool A, site-wide auditor (this engine, run over all posts) - (future) seo_validate.py — Tool C, pre-publish validator (same engine, one draft) Design note: every check is an independent function registered in RULES. To add a rule, write a function (post) -> list[Violation] and append it to RULES. The auditor and the validator both just call check_post(); they never re-implement a check. """ import re from collections import namedtuple SITE_HOST = "theexclusionzone.com" # ---- thresholds (single source of truth, reused by validator) ------------- META_TITLE_MAX = 60 META_DESC_MAX = 145 CUSTOM_EXCERPT_MAX = 300 MIN_INTERNAL_LINKS = 2 # ---- severity weights (used to rank "worst first") ------------------------ HIGH, MED, LOW, INFO = 3, 2, 1, 0 SEV_NAME = {HIGH: "HIGH", MED: "MED", LOW: "LOW", INFO: "INFO"} # The Edition-main theme injects BlogPosting JSON-LD globally in default.hbs # ({{#is "post"}} ...