Files
felhom.eu/REPORT-m3-2026-10-11.md
T
admin a7480172ab
gates / gates (push) Failing after 12m29s
gates: site gate 22 - the media-aware CSS leak check the phone bug needed
The two defects the operator found on his own phone are fixed and live since
5aeb36b5; this is what pins them so they cannot come back silently.

site_gates.py gate 22 parses site.css and shell.css into
(media context, selector, declarations) and fails on any property site.css
declares on a selector shell.css also styles that nothing overrides - neither
shell.css itself nor a `.shell ...`-scoped reset. site.css loads first, so
"later wins" is per PROPERTY, not per rule. Today: 689 site rules vs 119 shell
rules, 9 shared selectors, 0 leaks. .hamburger-box / .hamburger-line are an
explicit allow-list with the reason beside them.

It is media-aware precisely because the check it replaces was not. The STOP-1
leak diff excluded @media blocks and reported "exactly six" leaking
declarations; the real number is forty, and the worst of them
(@media (max-width: 900px) .nav-links { position: fixed; right: -100% })
parked the drawer's menu off-canvas and shipped.

Two decoys in test_gate_decoys.py, both the exact shape that went live, both
seen to convict:
  site/shell-css-leak-in-media  the body:not(.shell) scope taken back off that
                                one rule - the gate names the media query, the
                                selector and `right: -280px`
  site/footer-outside-main      <main> closed early on gyik.html - gate 3b's line
They plant and restore BYTES, with the anchor translated to the file's own line
ending: these files are CRLF in a Windows worktree and LF in a Linux one, and
replace_in's text-mode round trip would have rewritten a whole file on one side.

Also: CHANGELOG entries for both areas, the M3 report corrected where it quoted
its own wrong "exactly six", and one plain-language STATUS line.
2026-10-11 18:08:13 +02:00

132 lines
7.9 KiB
Markdown

# REPORT — M3: the website in the controller's shell (2026-10-11)
> `REPORT-<topic>.md`, not `REPORT.md`: that file belongs to another session and is overwritten
> per session.
## In plain words
The website now looks and works like the box's own dashboard: a left menu with your logo, the phone
version with a slide-out menu, and the same cards and buttons the controller uses. The pages say
exactly what they said yesterday. **The whole site switched at once**, so nothing is half old and
half new.
Two decisions you made during the run: the small **dashboard window** sits beside the headline
rather than a second copy of the logo, and the first menu item is **„Kezdőlap"**. You also chose to
have the **English home page rebuilt as a real twin** of the Hungarian one before switching, which
is what happened.
## What is live
20 pages: 12 Hungarian (including the hidden prices page) and 8 English. `website/preview/` is gone
entirely, taking the A, M1, M2 and M3 studies with it.
| | before | after |
|---|---:|---:|
| Home page height, desktop | 10 967 px | **4 340 px** |
| Home page, first load | 13 requests / 308 KB | **12 requests / 282 KB** |
| Third-party hosts | 0 | **0** |
| Em dashes on the home page | 18 | **0** |
| Em dashes replaced site-wide | — | **326 across 17 pages** |
## The two decisions, as answered
1. **Beside the headline: the dashboard window** (not the logo). The sidebar already shows the logo
and wordmark, so a second copy would have been the same mark twice on one screen.
2. **First menu item: „Kezdőlap"** (not „Indítópult"). The home page is not a launcher, and a
first-time visitor reads „Kezdőlap" without needing to know the product.
## What the controller and the website now share
Recorded in `documentation/design/design-system.md` §Shell.
| | Shared | Website owns | Controller owns |
|---|---|---|---|
| The 18 tokens | **yes**, byte-identical in both `:root` blocks | — | — |
| The shell: sidebar, top bar, drawer | **yes** — `shell.css` is a copy | the menu items, the wordmark, the sidebar button, the globe's targets | its own menu, its POST language form |
| Atoms: `.btn*`, `.alert*`, `.app-info-card`, `.launch-*`, `.form-*` | **yes**, same copy | — | — |
| Page content and layout | no | all of it | all of it |
**How a change flows:** the controller changes first; the website's copy is regenerated the same
week by re-running the generator against the controller's new commit. **A cross-repo gate was
deliberately not built** (your brief) — the shell should settle first.
## Proof, not assertion
- **Head tags** captured on all 19 pages before the switch and compared after
(`audits/m3-2026-10-11/head-before.json` / `head-after.json`). The **only** difference anywhere is
the dash substitution inside the two FAQ pages' `FAQPage` JSON-LD — proven by applying the same
substitution to the before copy and getting an exact match.
- **Visible text** identical to the live pages, word for word. **Legal texts identical with no
substitution permitted at all** (1 396 and 608 words).
- **Live read-back of all 20 URLs:** 200, sidebar, footer, legal link and `?v=22` on every one.
- **No page overflows at 390 px**; the drawer opens, closes on Escape and returns focus.
- **No contrast failures**, measured with translucent ancestors composited.
## Five faults found by measuring, which looking would not have found
1. **The home page was about to go live `noindex, nofollow`**, having also lost meta keywords, meta
author, all seven Open Graph tags, all four Twitter tags and the `LocalBusiness` JSON-LD — its
head was hand-built while every other page carried its live one over. The head-tag diff caught it.
2. **The footer had been deleted from all 19 pages**, taking the only route to the Adatkezelési
tájékoztató and the Feltételek, the operator's name and `info@felhom.eu`. The legal pages are in
no menu, so they would have become unreachable.
3. **168 words silently dropped** — the „Fontos tudnivalók" / „Good to know" box on both apps pages
and the 404's English line — by a page-header transform that kept only the `<h1>` and first
paragraph. Found by a word-level diff.
4. **The sidebar rendered as a horizontal row** across the content column, because „later wins" is
per property and the controller's `.nav-links` never declares `display`. Diffing the two files'
declaration sets found six such leaks; only this one was visible. **That diff was wrong, and the
section below says how** — the real number was forty.
5. **The contact pages' header slid under the sidebar** (content column at x=642 instead of 240,
form at two-thirds width) because those pages keep their header outside `<main>`.
## Fixed along the way, small enough not to file
- **`/letoltes` and `/adatkezeles` scrolled sideways on a phone** — 609 px and 478 px at a 390 px
viewport, **on the live site, before any of this**: a 64-character checksum and a long legal URL.
- **R-930 arrived a second time.** Fixing the website's `.cta-button` had not fixed the
*controller's* `.btn-primary`, which the shell imports; it measured 4.01:1 again. Your existing
remedy applied. `.nav-group-label` was 3.14:1 and moved to `--text-2`.
## Two defects a real phone found, after the switch
Reported by you, from your own phone, hours after it went live. Both were mine. Fixed, live as
`?v=23`, and read back on all 20 pages at 390 / 860 / 1440 px.
1. **The phone menu was empty.** The drawer slid open correctly and had nothing in it. `site.css`'s
old mobile nav still reached the shell's sidebar: under `@media (max-width: 900px)` it sets
`.nav-links { position: fixed; right: -100% }`, which parked the menu off-canvas *inside* the open
drawer. Every old-chrome selector (29 occurrences) is now scoped `body:not(.shell)` — scoped, not
deleted, so a page without the shell still works.
2. **The footer rendered as a second column** at the top right of 16 pages. `body` is a flex row on a
shell page, and my insert moved the footer inside `<main>` only on pages that *ended* with
`</main>`; a page with a `<script>` after it kept the footer as a direct child of `body`.
**The first one is a failure of my own check, not bad luck.** The leak diff I ran at STOP 1 — the one
whose „exactly six" this report quoted above — **excluded `@media` blocks**. Media-aware, the number
is **forty**, and the worst of them only apply below 900 px, which is exactly why the desktop screens
I took looked right. A check that silently skips part of its subject is not a check: it returned a
confident, wrong number, and I believed it rather than the phone.
**Both are now gated, each red-proofed by putting the live defect back:** gate 3b requires every shell
page's footer to sit inside `<main class="content">`, and the new **gate 22** compares the two
stylesheets **media-aware** and fails on any declaration of `site.css`'s that still reaches a shell
page. Today it reads 689 site rules against 119 shell rules, 9 shared selectors, **0 leaks**. The two
decoys (`site/shell-css-leak-in-media`, `site/footer-outside-main`) are the exact shapes that shipped.
## Still open
- **R-931** — felhom.eu still serves **nothing compressed**. `shell.css` adds 15 KB per page, all of
it uncompressed. This is now the cheapest win on the site by a wide margin.
- **R-932** — eight catalog strings carry an em dash and show on real customers' boxes.
- **The controller has the same two contrast defects** on its own screen (`.btn-primary` 4.01:1,
`.nav-group-label` 3.14:1). Fixed for the website only; that repo was read-only this session.
- **No cross-repo gate** keeps `shell.css` in step with the controller, by your instruction.
## Gates and register
`site_gates.py` green throughout, now with gate 22; full `repo_gates.py --fast` green on DooPlex,
decoy suite included. Register unchanged at 128 — nothing filed, because everything found was either
fixed in the session or already has a row, and the two live defects were found, fixed and pinned the
same day.