website: M3 part C - all 18 remaining pages moved into the shell
gates / gates (push) Successful in 8m50s
gates / gates (push) Successful in 8m50s
Staged under /preview/m3/. Nothing live. 19 shell pages in total with the home.
Each page keeps its own <head> byte-for-byte apart from two additions (shell.css
and the no-js/js hook), so title, meta description, canonical, hreflang, Open Graph
and JSON-LD all survive the move untouched. The body loses the website's
<nav>/<footer> and the old hamburger script, and gains the shell.
PROVED, not assumed - a word-level diff of every page's visible text, live vs
shell, with the nav and footer removed from both:
* 18 of 18 pages: visible text IDENTICAL after the one allowed substitution
* adatkezeles and feltetelek: identical with NO substitution permitted at all.
The legal texts are reviewed documents; the frame changed, the words did not.
That check earned itself immediately. The first version of the page-header
transform rebuilt the block from its <h1> and first <p> and SILENTLY DROPPED the
rest: the "Fontos tudnivalok" / "Good to know" disclaimer banner on both apps
pages and the 404's English line - 168 words across three pages. Nothing looked
wrong on the page. The diff found it.
Em dashes: 318 replaced with the Hungarian gondolatjel across 16 pages (gyik and
en/faq 104 each). The FAQ pages' JSON-LD is swept with the SAME substitution, so
gate 17's equality with the visible answers still holds - it does, on both.
scripts/site_gates.py:
* SHELL now holds all 19 pages.
* is_en(): a page is English if it is a TWINS value OR lives under an en/
directory. Without the second half the dash-language, <html lang> and
no-Hungarian gates all judged preview/m3/en/* as Hungarian - 30 false fails.
* norm_block() also drops `is-open` and `aria-expanded`, because the shell
renders the nav group containing the active page open, exactly as the
controller does, and that legitimately differs per page.
The last change LOOSENS a check, so it was red-proofed BOTH ways: a one-character
difference in one menu label still convicts, and a state-only difference (the
active marker moving to another item) correctly does not.
One generator now owns the shell. The home page's content comes from m3.py and its
shell from the same function every other page uses, so the two cannot drift - which
they already had, and gate 3b caught it.
This commit is contained in:
+45
-8
@@ -120,12 +120,43 @@ MOCKUPS = {os.path.join("preview", "m1", "index.html"),
|
||||
# every live page becomes one of these. They keep every other check; what changes for them is
|
||||
# WHICH block has to be identical across the set: the sidebar, not the nav and footer. Gate 3
|
||||
# below does both, so there is one identity gate rather than two.
|
||||
SHELL = {os.path.join("preview", "m3", "index.html")}
|
||||
SHELL = {
|
||||
os.path.join("preview", "m3", 'index.html'),
|
||||
os.path.join("preview", "m3", 'alkalmazasok.html'),
|
||||
os.path.join("preview", "m3", 'technologiak.html'),
|
||||
os.path.join("preview", "m3", 'biztonsagimentes.html'),
|
||||
os.path.join("preview", "m3", 'gyik.html'),
|
||||
os.path.join("preview", "m3", 'teszteles.html'),
|
||||
os.path.join("preview", "m3", 'kapcsolat.html'),
|
||||
os.path.join("preview", "m3", 'letoltes.html'),
|
||||
os.path.join("preview", "m3", 'adatkezeles.html'),
|
||||
os.path.join("preview", "m3", 'feltetelek.html'),
|
||||
os.path.join("preview", "m3", '404.html'),
|
||||
os.path.join("preview", "m3", "en", 'index.html'),
|
||||
os.path.join("preview", "m3", "en", 'apps.html'),
|
||||
os.path.join("preview", "m3", "en", 'technology.html'),
|
||||
os.path.join("preview", "m3", "en", 'backups.html'),
|
||||
os.path.join("preview", "m3", "en", 'faq.html'),
|
||||
os.path.join("preview", "m3", "en", 'testing.html'),
|
||||
os.path.join("preview", "m3", "en", 'contact.html'),
|
||||
os.path.join("preview", "m3", "en", 'download.html'),
|
||||
}
|
||||
|
||||
PAGES = list(TWINS) + list(TWINS.values()) + sorted(NO_TWIN) + sorted(MOCKUPS) + sorted(SHELL)
|
||||
EN_PAGES = set(TWINS.values())
|
||||
HU_PAGES = set(PAGES) - EN_PAGES - MOCKUPS - SHELL
|
||||
ANALYTICS_EXEMPT = {"szolgaltatasok-nonpublic.html"} | MOCKUPS
|
||||
|
||||
|
||||
def is_en(p):
|
||||
"""A page is English if it is a TWINS value OR it lives under an `en/` directory. The second
|
||||
half matters for the shell pages staged at preview/m3/en/*, which are not in TWINS yet: without
|
||||
it the dash-language, <html lang> and no-Hungarian gates all judged them as Hungarian."""
|
||||
return p in EN_PAGES or p.split(os.sep)[0] == "en" or (os.sep + "en" + os.sep) in p
|
||||
|
||||
|
||||
def lang_of(p):
|
||||
return "en" if is_en(p) else "hu"
|
||||
ANALYTICS_MARK = "https://stats.felhom.eu/script.js"
|
||||
SITE = "https://felhom.eu"
|
||||
|
||||
@@ -162,9 +193,19 @@ GLOBE_ITEM_RE = re.compile(r'<a href="([^"]*)" lang="([^"]*)" hreflang="([^"]*)"
|
||||
r'( aria-current="true")?>([^<]*)</a>')
|
||||
|
||||
|
||||
def _drop_state_classes(m):
|
||||
"""Remove the markers that legitimately differ per page from a class list: `active` on the
|
||||
current item, and `is-open` on the nav group containing it (the shell renders that group open,
|
||||
exactly as the controller does). Everything else in the class must match."""
|
||||
keep = [c for c in m.group(1).split() if c not in ("active", "is-open")]
|
||||
return 'class="%s"' % " ".join(keep) if keep else ""
|
||||
|
||||
|
||||
def norm_block(b):
|
||||
b = b.replace(' class="active"', "")
|
||||
b = re.sub(r'\s*aria-current="[^"]*"', "", b)
|
||||
b = re.sub(r'\s*aria-expanded="[^"]*"', "", b) # open/closed state of the same group
|
||||
b = re.sub(r'class="([^"]*)"', _drop_state_classes, b)
|
||||
# the globe is the one nav item whose content differs per page (its targets, its current mark, its label) —
|
||||
# gate 13 checks all of that; here only its presence must match
|
||||
b = GLOBE_RE.sub('<details class="lang-globe"/>', b)
|
||||
@@ -246,7 +287,7 @@ for p in sorted(SHELL):
|
||||
if not m:
|
||||
fail("%s: no <nav class=\"sidebar\"> block — a shell page carries the shell" % p)
|
||||
continue
|
||||
_shell_by_lang.setdefault("en" if p.startswith("en" + os.sep) else "hu", []).append((p, norm_block(m.group(0))))
|
||||
_shell_by_lang.setdefault(lang_of(p), []).append((p, norm_block(m.group(0))))
|
||||
for _lang, _members in sorted(_shell_by_lang.items()):
|
||||
_ref_p, _ref = _members[0]
|
||||
_bad = 0
|
||||
@@ -331,10 +372,6 @@ for p, s in pages.items():
|
||||
# gate 13: twins — both ways, matching alternates, the globe pointing at the twins
|
||||
|
||||
|
||||
def lang_of(p):
|
||||
return "en" if p in EN_PAGES else "hu"
|
||||
|
||||
|
||||
def check_globe(p, lang, urls=None):
|
||||
"""Exactly one globe; its label in the page's language; one item per LANGS entry, in order, lang/hreflang equal to
|
||||
the entry; the page's own language is the only current/aria-current item; with `urls`, each item's target."""
|
||||
@@ -390,7 +427,7 @@ for p, s in pages.items():
|
||||
# gate 14: the lang attribute
|
||||
for p, s in pages.items():
|
||||
m = re.search(r'<html lang="([^"]+)"', s)
|
||||
want = "en" if p in EN_PAGES else "hu"
|
||||
want = "en" if is_en(p) else "hu"
|
||||
if not m or m.group(1) != want:
|
||||
fail("%s: <html lang=%r> — the %s set needs lang=%r" % (p, m and m.group(1), "English" if want == "en" else "Hungarian", want))
|
||||
|
||||
@@ -477,7 +514,7 @@ if not _pos or not _pos2 or _neg:
|
||||
else:
|
||||
print(" no-HU matcher controls OK (positive 'Jelentkezz be'/'Kapcsolat' convict, negative 'Angola…' does not)")
|
||||
|
||||
for p in sorted(EN_PAGES):
|
||||
for p in sorted(x for x in pages if is_en(x)):
|
||||
s = pages.get(p)
|
||||
if s is None:
|
||||
continue
|
||||
|
||||
Reference in New Issue
Block a user