feat(brand): evig repairs becomes evig technicians, and evig stops asking for printers - #382
Merged
Merged
Conversation
…king for printers
Three changes from the same focusing pass, all of them cases where the copy
described an organisation the code had already outgrown.
## The division is named after the person, not the service
`evig repairs` → `evig technicians`. "Repairs" names what happens; a user is
looking for someone who will do it. The surface has worked that way for a long
time — post a request, receive offers from technicians nearby, choose one, with
a budget filter that already splits "Gratis / Community" from "Mit Budget" —
only the naming lagged behind the product.
Contained to `src/config/divisions.ts` plus the `divisions.items.<id>` key in
eight locales, because the wordmark is composed (`${ORG.name} ${id}`) and every
consumer derives from the array. No component changed.
## IT-Hilfe stops promising charity
The page called itself "Kostenlose Community-Reparatur" and said "kostenlos"
three times over: meta title, meta description, subtitle, tagline. That framing
does two bad things at once — it hides the marketplace the code implements, and
it forecloses the half of the model where a technician actually earns. Rewritten
to what it is: describe the problem, get offers, choose. "Über die Community
gratis oder fair bezahlt" keeps the free path visible without making it the
whole promise.
Fixed alongside: `itHelp.hub.subtitle` was stored as literal ENGLISH in es, fr,
it, ja and ko. Not a missing key — a wrong value, so no fallback could catch it
and no missing-key audit could see it. Five locales showed an English sentence
in the middle of a translated page.
## No more printers
The donation pages solicited "Laptops, Desktop-PCs, Monitore, Tastaturen,
Mäuse, Drucker" while the new homepage copy says evig does not deal in
printers. One of the two had to go. A printer is the archetype of what evig
deliberately does not take: low value, hard to refurbish, and — per
co2-impact.ts, which already refuses to publish a factor for the category —
without a defensible open number, so we could not even honestly claim a saving
for keeping one alive. GPUs take their place in the list, which is what the AI
thesis actually needs.
The erfassung category '60' (Drucker & Scanner) deliberately STAYS. Existing
inventory rows point at it, and deleting a category that historical records
reference would corrupt them. Not soliciting new ones is the change; rewriting
the past is not.
## /revamped deleted
294 lines selling "die REVAMPED-Zertifizierung … unser exklusives REVAMPED-
Label" — the previous organisation's name, as a product label, after the
rebrand. It was orphaned from nav and footer but still listed in the sitemap,
so it was indexable. It also advertised a certification for computers "we
build" on behalf of a service flagged `available: false`, and its inbound CTA
copy had sat unmaintained long enough to contain a German grammar error ("Hol
sich deine" for "Hol dir deine"). Page, messages, sitemap entry and the
inbound certification block are all gone. If evig wants a quality label later,
it belongs on the QC Prüfsiegel the intake pipeline already produces.
Also removed `ROUTES.public.transparenzKennzahlen` — a route constant used by
nothing, pointing at a page that deliberately calls notFound().
## One baseline moved, deliberately
Two new "wrong language" findings, both false positives of the same kind as the
last batch: "Trovare un tecnico" (correct Italian) and "Encontrar a quien lo
repare" (correct Spanish), each scored `own 0` because the words are absent
from the detector's own word list for that language. Verified by reading, then
accepted.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
github-actions Bot
pushed a commit
that referenced
this pull request
Aug 26, 2026
…ect (#387) Third time in three PRs that this gate flagged correct Italian and Spanish — "Trovare un tecnico", "Encontrar a quien lo repare", "LO QUE HACEMOS" and seven more, none of them defects. Twice I verified them by hand and bumped the baseline. The rule says the third time you stop fixing instances and close the class. ## Why it was wrong Not a threshold problem — HOLES in the stop-word lists. `un` was listed only under fr; it had `una`/`uno` but not the masculine `un`. So "Trovare un tecnico" scored Italian 0.00, French 0.33 and got flagged. Spanish was missing `lo` and `a` while Italian had `lo`, which is why "Encontrar a quien lo repare" looked Italian. A hole in a list makes CORRECT text look foreign. Filling the holes then made it worse in the other direction: teaching es the word `su` immediately made correct Italian ("Linux su vecchi ThinkPad") look Spanish, and `e`, `non`, `nos` did the same across the other pairs. Sibling Romance languages share their function words. A bag-of-stop-words comparison cannot separate them, and no amount of dictionary work will change that. ## What it does now It detects what it CAN detect: untranslated **English or German** sitting in a translated file. Those function words barely overlap with Romance or CJK ones, and that is the leak that actually happens here — DE is the source language and EN the pivot. Sibling-language comparison is dropped. Three guards, each earned: - LEAK_SOURCES = ['en','de'] — only judge against languages it can tell apart. - MIN_TOKENS_FOR_LANGUAGE_GUESS = 6 — the heuristic's resolution is 1/N; on a three-word string one shared article moves the ratio by 0.33, clearing the threshold on its own. - A script guard, because \w is ASCII-ONLY in JavaScript even under /u, so `[^\W\d_]` counted Hangul, kana and Cyrillic as ZERO letters and my first attempt at this guard silently did nothing. It uses \p{L} now. Without it a Korean sentence containing "evig" and "Revamp-IT" scores as English on those crumbs. Proved by mutation, not by assertion: 16 cases, eleven correct-language strings (it/es/fr/ko/ja/ru, including CJK carrying Latin brand names) all clean, five real English/German leaks all still caught. ## What the fix immediately found **Real untranslated English shipped to five locales.** es, fr, it, ja and ko were all rendering English inside the IT-Hilfe hub — "Describe your issue and receive offers from technicians", "Browse profiles and contact someone directly", "Help as a technician — requests near you", "Register as a technician and help people nearby." — plus the privacy page's data-export sentence in ja and ko. The KEYS existed, so the missing-key audit passed; only the values were English, and the old detector could not see them. All translated here. This is the same class as itHelp.hub.subtitle in #382, which I found by reading a rendered page. The gate finds them now. ## And a dead storefront `shop.*` held 140 keys; three loading/error boundaries use SIX. The other 134 describe a storefront whose pages are pure `redirect()` calls to /marketplace — product grids, cart labels, category breadcrumbs, opening hours — shipped in every visitor's page payload in eight languages. Pruned: ~54KB of JSON, 6511 deleted lines. Liveness checked by namespace prefix, not just call sites (the lesson from home.newsletter), then proved by typecheck. Baseline lowered in the same commit, per the ratchet rule: 706 message findings → 84, with 632 resolved and 0 new. Also folded in (was #386, which deadlocked against this: its new Italian and Spanish headlines were flagged by the very detector this fixes): - /it-hilfe still showed "Computer reparieren, OS neu installieren, IT-Probleme lösen" as its H1 — a keyword list. #382 reframed the metadata and subtitle and missed the line a visitor reads first. It now matches the homepage pillar's link text exactly, so clicking "Jemanden finden, der es repariert" lands on a page with that headline. - "CHF 300.00" wrapped onto two lines on a 390px pool card. A price must not wrap; the title beside it gives way instead. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
github-actions Bot
pushed a commit
that referenced
this pull request
Aug 26, 2026
…av entries went nowhere (#388) Found by walking all 33 public pages rather than reading the code. ## Donations were going to Revamp-IT `/get-involved/donate` carried two hardcoded buttons: https://ko-fi.com/revampit https://github.com/sponsors/revampit On evig's own donate page. Someone clicking "spenden" funded the organisation evig span out of. evig has no Ko-fi and no GitHub Sponsors account, so there was nothing to repoint them at — the choice was remove them or keep collecting for someone else. Removed; the bank transfer and the device-donation path above and below them are evig's real routes. Two more links pointed at the wrong GitHub org: the "contribute code" button (github.com/revampit) and the CO₂ page's "check our maths" link (github.com/g-but/revampit — the previous org's repo AND a retired handle). Both derive from EXTERNAL_LINKS.sourceCode now. ## Two nav entries rendered <a href=""> `Marktplatz → evig Shop` read EXTERNAL_LINKS.shopware and `Lernen → Wiki` read EXTERNAL_LINKS.wiki. Both are empty strings — evig has neither a Shopware storefront nor a wiki. Neither MegaMenuContent nor MobileMenuNav filters empty hrefs, so both shipped as `<a href="" target="_blank">`: the FIRST item of the Marktplatz menu opened a blank duplicate of the current page in a new tab. The shop entry's comment still read "The official RevampIT storefront is the external Shopware shop", while .claude/CLAUDE.md says evig has one store and it is /marketplace. Nothing could have caught this: not a missing key (the labels exist), not a broken route (there is no route), not a type error (`''` is a valid string). So the gate is new — `navigation-links-resolve.test.ts` asserts every href in the real exported tree is non-empty and well-formed, which also covers the derived builders. Proved by mutation: planting the empty href back turns "every href is present and non-empty" red and leaves the other three green. ## Three dead links shipped in DE copy - faq.groups[4].items[1] sold "die REVAMPED-Zertifizierung" and linked to /revamped — a 404 since #382 deleted that page. My own regression: I removed the page and its inbound CTA but not the FAQ entry. REVAMPED is the previous org's product name, so the question goes rather than the link. - `Lernen → Guides` pointed at /knowhow#guides; the Guides card ON that page pointed at /#guides. Neither anchor exists — /knowhow's only id is `ressourcen` — and the two did not even agree with each other. There are no guides. ## Lernen now points at what evig actually owns /workshops renders "0 Workshops · Aktuell sind keine Workshops geplant" and /blog renders nothing, while the 43-entry open-source alternatives registry (1029 lines, real, indexed) and the Linux page with its distro matrix sat three levels down under Dienstleistungen. Both are in Lernen now, where someone looking to learn would look, alongside a Ressourcen entry pointing at the curated-links section that does exist. ## /knowhow claimed Revamp-IT's history as evig's "Wir teilen unser 16+ Jahre Knowhow" — on an org founded 2026. That is exactly what .claude/CLAUDE.md forbids ("evig claims no 'since 2003' of its own"). Its H1 also sold "Vintage Hardware", repeated in the meta description and the guides card — the opposite of what evig sells, which is machines good enough for real work today. Rewritten to Linux, open software and the practical use of AI, in all eight locales. npm run verify green: lint, umlauts, chrome, docs, compliance, typecheck, 7750 tests (534 suites), production build. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Three changes from the same focusing pass. Each is a case where the copy described an organisation the code had already outgrown.
The division is named after the person, not the service
evig repairs→evig technicians. "Repairs" names what happens; a user is looking for someone who will do it. The surface has worked that way for a long time — post a request, receive offers from technicians nearby, choose one, with a budget filter that already splits "Gratis / Community" from "Mit Budget". Only the naming lagged behind the product.The rename is two lines in
src/config/divisions.tsplus thedivisions.items.<id>key in eight locales — the wordmark is composed (${ORG.name} ${id}) and every consumer derives from the array, so no component changed.IT-Hilfe stops promising charity
The page called itself "Kostenlose Community-Reparatur" and said kostenlos three times over: meta title, meta description, subtitle, tagline. That framing does two bad things at once — it hides the marketplace the code implements, and it forecloses the half of the model where a technician actually earns.
Rewritten to what it is: describe the problem, get offers, choose. "Über die Community gratis oder fair bezahlt" keeps the free path visible without making it the whole promise.
Found and fixed alongside:
itHelp.hub.subtitlewas stored as literal English in es, fr, it, ja and ko. Not a missing key — a wrong value, so no fallback could catch it and no missing-key audit could see it. Five locales rendered an English sentence in the middle of a translated page.No more printers
The donation pages solicited "Laptops, Desktop-PCs, Monitore, Tastaturen, Mäuse, Drucker" while the new homepage copy says evig does not deal in printers. One of the two had to go.
A printer is the archetype of what evig deliberately does not take: low value, hard to refurbish, and — per
co2-impact.ts, which already refuses to publish a factor for the category — without a defensible open number, so we could not even honestly claim a saving for keeping one alive. GPUs take their place in the list, which is what the AI thesis actually needs.The erfassung category
'60'(Drucker & Scanner) deliberately stays. Existing inventory rows point at it, and deleting a category that historical records reference would corrupt them. Not soliciting new ones is the change; rewriting the past is not./revamped deleted
294 lines selling "die REVAMPED-Zertifizierung … unser exklusives REVAMPED-Label" — the previous organisation's name, as a product label, after the rebrand. It was orphaned from nav and footer but still listed in the sitemap, so it was indexable. It also advertised a certification for computers "we build" on behalf of a service flagged
available: false, and its inbound CTA copy had sat unmaintained long enough to contain a German grammar error ("Hol sich deine" for "Hol dir deine").Page, messages, sitemap entry, and the inbound certification block are all gone. If evig wants a quality label later, it belongs on the QC Prüfsiegel the intake pipeline already produces — not on a name evig no longer carries.
Also removed
ROUTES.public.transparenzKennzahlen: a route constant used by nothing, pointing at a page that deliberately callsnotFound().One baseline moved, deliberately
Two new "wrong language" findings, both false positives of the same kind as the last batch: "Trovare un tecnico" (correct Italian) and "Encontrar a quien lo repare" (correct Spanish), each scored
own 0because the words are absent from the detector's word list for that language. Verified by reading before accepting.Verification
npm run verifygreen on this exact tree: lint, umlauts, chrome, docs, compliance, typecheck, 7746 tests, production build.🤖 Generated with Claude Code