""" Accepted SEO exceptions — consciously-waived findings for SPECIFIC posts. This is an A-side (auditor) REPORTING filter, NOT a rule change. The shared rule engine (seo_rules.py) still CHECKS every rule on every post; the auditor simply moves a matching violation into a separate "Accepted exceptions (won't fix — documented)" section so the headline "issues to fix" count reflects only genuinely-actionable items. Each waiver carries its REASON (no silent skips). Structure: EXCEPTIONS[rule_family][slug] = "documented reason" Scope: - A waiver applies ONLY to the named rule family for the named slug. Any OTHER rule the same post violates still surfaces as a real issue. - A waiver is matched against a Violation whose `rule` equals the family key or starts with "." — so "internal_links" covers "internal_links.too_few". - If a post later stops violating the rule (e.g. a link is added and it clears the threshold), there's simply no violation to waive — the waiver is moot. Tool C (seo_validate.py, pre-publish validator) deliberately does NOT consult this registry: exceptions are per-EXISTING-post decisions; a brand-new draft is held to the full standard. """ EXCEPTIONS = { # internal_links < 2 — these posts are intentionally left as-is because there # is no honest 2nd internal-link target in their prose; forcing one would hurt # quality. (Decided 2026-06-23.) "internal_links": { "roswell-1947-ufo-incident": "1 link (Spielberg); no 2nd entity in prose maps to an article — " "forcing a link would hurt quality.", "manises-1979-spain-ufo-incident": "1 link (Canary Islands); no 2nd entity in prose maps to an article.", "betty-barney-hill-1961-abduction": "1 link (alien abduction → travis-walton, thematic); no 2nd honest target.", "malmstrom-1967-ufo-nuclear-missiles-incident": "1 link (Grusch); the only entity named in the prose.", "rendlesham-forest-incident-1980": "0 links; genuinely isolated — no entity in prose maps to one of our articles.", "phoenix-lights-1997": "0 links; only thematic candidates are stretches — left as-is.", "canary-islands-1976-ufo-sighting": "1 link (reciprocal → manises); no honest 2nd entity in prose — " "Spanish case, self-contained.", "chiles-military-declassified-uap-files-cefaas-groundbreaking-investigation-of-unexplained-aerial-phenomena": "1 link (→ pursue-release-3, the 294 files); no 2nd verbatim entity " "in prose — self-contained Chilean case.", "levelland-1957-texas-ufo-vehicle-interference": "1 link (→ project-blue-book, la única entidad del corpus nombrada en " "la prosa; lo demás es Hynek y 'ball lightning', sin artículo propio). " "El enlace previo a AARO era un destino de conveniencia: Levelland se " "creó el 30-jun y el artículo de Blue Book no existía hasta el 1-jul, " "así que el autofill enlazó a lo más cercano disponible. Repuntado al " "destino correcto el 2026-07-18.", "hundreds-watched-in-broad-daylight-the-westall-ufo-mystery-that-australia-still-cant-explain": "0 links; la prosa no nombra ningún otro caso del corpus — episodio " "escolar australiano, autocontenido. (Revisado 2026-07-18, antes de " "su publicación del 6-ago.)", "colares-1977-brazil-air-force-ufo-investigation": "1 link (→ varginha, el otro caso brasileño); lo único más que nombra " "es 'Operation Saucer', que es su propia operación y no tiene artículo. " "(Revisado 2026-07-18, antes de su publicación del 24-ago.)", "tassili-najjer-cave-paintings-ancient-astronaut-theory": "1 link (→ gimbal-gofast); ningún otro caso del corpus aparece en la " "prosa — arqueología sahariana, autocontenida. (Revisado 2026-07-18.)", "missing-scientists-theory-youtube-white-house-2026": "1 link (→ grusch-capitol); trata de la cadena mediática, no de casos " "UAP — no hay 2ª entidad del corpus en la prosa. (Revisado 2026-07-18.)", "grusch-capitol-june-9-2026-uap-disclosure": "1 link (→ la investigación completa, que es lo correcto). Es el ADELANTO " "del evento, con canonical_url apuntando a esa investigación: sus señales " "se consolidan allí, así que forzar enlaces aquí no aporta. " "(Revisado 2026-07-18, ver project-en-seo-recovery.)", "tehran-1976-iranian-f4-ufo-incident": "0 links; prose names no case we have an article for (only Klass, " "Jafari, the DIA report) — self-contained. Thematic candidates " "(Malmstrom, Levelland, Manises) appear nowhere in the text. " "(Reviewed 2026-07-18.)", }, } def accepted_reason(rule, slug): """Return the documented waiver reason if (rule, slug) is an accepted exception, else None. Matches a rule-family key to a Violation whose `rule` is the key itself or "." (e.g. family "internal_links" matches "internal_links.too_few"). """ for family, slugs in EXCEPTIONS.items(): if (rule == family or rule.startswith(family + ".")) and slug in slugs: return slugs[slug] return None