solcom / P2503-84 · PR-Review · 2026-05-16 · fixed-point: origin/develop

P2503-84 — Header, Main Nav & Footer (F-40 Navigation & Seitenstruktur)

NK
Nico Köhle
1 Commit · PR #164342
feature/P2503-84 develop
+2026 / −23738 files
Findings: standards=6 (3 hard, 3 judgement) · spec=8 (3 missing, 3 scope-creep, 2 incorrect-impl)
Worst: aria-current="page" ist an sub_item.in_active_trail gebunden — Drupal setzt in_active_trail=true auf jedem Vorfahren, nicht nur auf der aktuellen Seite. Verstoß gegen WCAG 2.1 SC 1.3.1 (ADR-0027 §Entscheidung).

Risk map

safe worth a look needs attention

Standards

menu--social.html.twig · src/main.css · footer.twig · navbar.tailwind.css — Hardcoded brand hex Hard Violation
HardKanonische Brand-Hex statt CSS-Tokens

menu--social.html.twig:32 nutzt bg-[#bedc00] !text-[#001f46]. src/main.css:452,454,458,464 enthält #f4ffab, #00459d (×3), #fdfbf4. footer.twig hat 'border-[#bedc00]', 'decoration-[#bedc00]', 'text-[#f4ffab]', 'bg-[#001f46]'. navbar.tailwind.css nutzt var(--brand-dark-blue, #001f46) mit Hex-Fallback.

Regel: „Jeder kanonische Brand-Hex (#BEDC00, #001F46, …) im Code muss über die korrespondierende CSS-Variable (--brand-lime, --brand-dark-blue, …) referenziert werden." #f4ffab und #fdfbf4 existieren in theme.brand.css nicht — entweder Token anlegen oder Verwendung begründen.

Quelle: .claude/agents/solcom-brand-reviewer.md ↔ .claude/skills/solcom-styleguide/SKILL.md
menu--main.html.twig:43 — Inline-Twig-Ternary in HTML-Attribut Hard Violation
HardTwig-Ternary direkt im <a>-Tag

Code: <a ... {{ sub_item.in_active_trail ? 'aria-current="page"' : '' }}>. Vor das Tag ein {% set aria_current = sub_item.in_active_trail ? 'aria-current="page"' : '' %} und im Tag {{ aria_current }} rendern.

Quelle: web/themes/custom/byte_theme/AGENTS.md — „No Inline Control Structures in Attributes"
navbar.twig:109–116, 120–127 — Icon-Include ohne with_context: false Hard Violation
HardHamburger-Icon-Includes ohne Context-Isolation

Die beiden neu eingeführten include('@byte_theme/components/icon/icon.twig', { icon: 'list', ... })-Aufrufe haben kein drittes Argument with_context: false. AGENTS.md verlangt zur Vermeidung von Context-Pollution explizit with_context: false oder with ... only.

Pre-existing Includes (Close-Button, Placeholder-Block) sind nicht in Scope — nur die zwei neu in diesem PR hinzugefügten.

Quelle: web/themes/custom/byte_theme/AGENTS.md — „Always Use with_context: false or with only"
components/navbar/navbar.twig — Root-Container-Klasse geändert Judgement Call
Judgementcontainer mx-auto entfernt, md:px-20md:px-10, neu w-full

ADR-0008 spezifiziert „Container 1280 px mit 80 px Horizontal-Padding". Mit dieser Diff ist die navbar nicht mehr 1280 px-bounded; medium-Breakpoint-Padding sinkt von 80 px auf 40 px. Wenn die äußere Page-Shell die Constraint liefert, ist das OK — statisch nicht verifizierbar.

Quelle: docs/adr/0008-solcom-header-navbar-slot-refactor.html
menu--social.html.twig — URL-Substring-Sniffing zur Plattform-Erkennung Judgement Call
Judgement{% if 'xing.' in url_str %} als Plattform-Detection

Plattform-Erkennung über Substring-Matching auf gerenderter URL ist fragil (Trailing-Whitespace, Query-Strings, URL-Aliases). Sauberer wäre item.original_link.getPluginId() oder ein dediziertes Plattform-Feld am Menüpunkt. Keine explizite Regel im Korpus — Advisory.

Quelle: nur Pattern-Hygiene, kein hard rule

Spec

menu--main.html.twig — aria-current="page" falsch gebunden Incorrect Implementation
Falsch implementiertaria-current="page" an in_active_trail statt an die exakte aktuelle Seite

Drupal setzt in_active_trail=true auf jedem Vorfahren im aktiven Trail, nicht nur auf der aktuellen Seite. Bei einem Sub-Item, das Vorfahre der aktuellen Route ist, vergibt der Template-Code fälschlich aria-current="page".

ADR-0027 §Entscheidung: „aria-current='page' auf dem aktiven Sub-<a>-Link (nicht auf dem Parent-Button)" — gemeint ist die aktuelle Seite, nicht der Trail. Verstoß gegen WCAG 2.1 SC 1.3.1 (Info and Relationships). Gate-on item.in_active_trail + Pfad-Equality, oder Route-Name-Equality.

Quelle: docs/adr/0027-navigation-dropdown-disclosure-wcag-aa.html §Entscheidung; PRD §Testing
components/navbar/navbar.js — Mobile-Scroll-Lock entfernt Missing Requirement
Gapdocument.documentElement.classList.add("navbar-modal-open") ist im isOpen-Setter weggefallen

Die CSS-Regel :root.navbar-modal-open { overflow: hidden } in navbar.tailwind.css:4 bleibt im Diff — wird aber nie mehr aktiviert. Folge: mobiler Overlay öffnet, Body-Scroll bleibt aktiv, CSS-Regel ist Dead-Code.

ADR-0027 §Consequences: „Hamburger-Toggle bleibt unverändert" — Scroll-Lock war vorher Teil davon.

Quelle: docs/adr/0027-…html §Consequences
.solcom-nav-sub-link — Arrow als Inline-SVG statt CSS-::before Incorrect Implementation
Falsch implementiertArchitekturentscheidung „::before-Lime-Arrow" nicht umgesetzt

ADR-0027 §Entscheidung: „Sub-Item CSS: .solcom-nav-sub-link — neue CSS-Klasse in src/main.css mit ::before-Lime-Arrow." PRD §Implementation: „führender Lime-Arrow via ::before-Pseudo-Element."

Implementation: <span class="solcom-nav-sub-link__icon"><svg …> als inline-DOM. Funktional ähnlich, aber Decision verletzt + zusätzliche DOM-Nodes pro Menüpunkt.

Quelle: docs/adr/0027-…html §Entscheidung; docs/prds/2026-05-13-…html §Implementation
azure-pipelines.yml — drush cr-Step ohne Spec Scope Creep
CreepCI-Pipeline-Änderung in Theme-/Navigations-PR

Diff fügt drush cr vor updatedb/cim in beiden Deploy-Stages hinzu. Operativ sinnvoll (Cache-Reset vor Update), aber weder in PRD, ADR-0027 noch Story-Hub spezifiziert — gehört in eigenes Infrastruktur-Ticket.

Quelle: keine — nicht in spec
menu--social.html.twig — Kompletter Rewrite ohne Spec-Bezug Scope Creep
CreepSocial-Menu mit URL-Sniff + SVG-Icon-Buttons + neue Icons (xing/linkedin/instagram)

PRD und ADR-0027 referenzieren nur menu--main.html.twig, navbar.js, src/main.css, HeaderTemplatesTest.php. Das Social-Menü liegt im Footer-Bereich, der explizit ausgeklammert ist.

Quelle: docs/prds/2026-05-13-…html §Implementation; ADR-0027 §Out of Scope
HeaderTemplatesTest.php — Test-Coverage-Lücken zu PRD-Kontrakten Missing Requirement
GapKeine Assertions für Enter/Space-Toggle und Underline-Suppression im aktiven Trail

PRD §Testing nennt Enter/Space als Kontrakt (native <button> deckt das, aber unverifiziert). main.css setzt @apply no-underline für .solcom-btn-link--nav.solcom-btn-link--active-trail — visueller Kontrakt der ADR ungeprüft.

Quelle: docs/prds/2026-05-13-…html §Testing; docs/adr/0027-…html §Consequences
Story-Hub F-40 — „Sprechende URLs" nicht adressiert, Hub nicht aktualisiert Missing Requirement
GapJira-Story nennt „sprechende URLs", PRD scoped es korrekt aus, Story-Hub bleibt offen

PRD §Out of Scope: „URL-Konventionen / Path Aliases — bereits implementiert (Pathauto), kein Handlungsbedarf." Korrekt ausgeklammert.

Aber: docs/stories/F-40-navigation-seitenstruktur.html §Akzeptanzkriterien sagt „Noch nicht definiert." PR transitioniert P2503-84 nach „Zu Review", ohne den Story-Hub mit dem Stand zu synchronisieren (erfüllt / explizit deferred). Verletzt project_story_hub_pattern.

Quelle: docs/stories/F-40-navigation-seitenstruktur.html; Memory project_story_hub_pattern