emails: copy has no automated language gate, and tests are the wrong fix #128
Etiketter
Inga etiketter
area/backups
area/ci
area/control-panel
area/identity
area/infra
area/observability
area/payments
area/security
area/storage
area/web
blocked
needs-info
needs-triage
ready-for-implementation
type
bug
type
chore
type
docs
type
epic
type
feature
type
task
wontfix
Ingen milstolpe
Inget projekt
Inga tilldelade
1 deltagare
Notiser
Förfallodatum
Inget förfallodatum satt.
Beroenden
Inga beroenden satta
Referens
bitborg/bitborg-web#128
Läser in…
Hänvisa till i nytt ärende
Ingen beskrivning angiven.
Ta bort grenen "%!s()"
Borttagning av en gren är permanent. Även om den borttagna grenen kan fortsätta existera en kort tid innan den faktiskt tas bort, kan det INTE ångras i de flesta fall. Vill du fortsätta?
Transactional email copy in
src/i18n/emails.tshas no automated protection of any kind — no tests, and no language check that runs unless somebody remembers to run it.This was a deliberate choice while building the sign-up journey, not an oversight, and it is recorded here so nobody rediscovers it as one. But the risk it accepted turned out to be real.
What actually went wrong
During that work the email copy was revised three times, each time fixing a genuine fault, each caught by a human reading it late:
None of these are typos. Each was fluent, plausible copy that said the wrong thing.
Why tests are probably the wrong tool
The obvious reflex is snapshot or equality assertions on the strings. That mostly asserts a string equals itself: it catches accidental deletion or a bad merge, and it catches none of the three faults above. Worse, it makes copy edits noisy — every intentional wording change becomes a test update, which trains people to update the expectation without reading it.
The failure mode here is semantic: does this sentence match what the link does, does it cover every user it addresses, is it grammatical. Assertions on literals cannot see any of that.
What would help instead
Run the existing content-style check automatically on changed content and i18n files, rather than on request. It already encodes the known faults as rules — including, since this work, the tagline form and keeping "passkey" in English — so it would at minimum stop the same mistakes recurring silently.
Candidate hook: the lefthook pre-commit path that already formats and lints staged files, scoped to
src/content/**andsrc/i18n/*.ts.Be honest about the ceiling. The checker is a regex heuristic. It cannot tell that a link labelled "start again" points at a continue flow, and it cannot judge tone. So this reduces recurrence of known faults; it does not catch a new instance of the class. Reviewing email copy by reading it, in both languages, stays necessary — the real value here is that the known faults stop needing a human to remember them.
Done when
A change to
src/content/**orsrc/i18n/*.tsruns the content-style check without anyone invoking it, and the check's failure output names the style-guide rule it is enforcing.