**French and German are live, and a guard that refused too much stopped leaving whole Portuguese
sentences on every locale page.** The editor asked for the other languages to be findable from the
front page. `fr` and `de` are now `publicado` in `dados/i18n/locales.json`, which makes three
languages beside the Portuguese page of record, 224 pages each, and a switcher on every page that
points at THIS page in the other language.

**German was translated the same way English and French were: from the 1 051-segment memory, never
from the render.** 998 segments at the start of this release, 457 of them still Portuguese in the
German column, 13 953 words. They went in batches against the Portuguese source with the English
translation beside it for disambiguation, which is what the content-addressed memory is for: a
segment is keyed by the hash of its own source text, so a segment translated once stays translated
however many of the 224 pages carry it, and a source that changes is a cache miss rather than a flag
somebody has to remember to set.

**The guillemet guard was refusing whole runs, and the report could not see it.** Anything inside
«…» on this site is somebody else's words, and a translated quotation is a misquotation — so
`build/locales.py` refused any text run containing a guillemet outright. The comment said this cost
«a handful of chrome lines their translation». It did not. It left **23 distinct runs Portuguese on
every locale page, 174 occurrences**, and the worst of them was the sentence on `/empresas/`
explaining what happens to a marker value such as «Independent» — a whole Portuguese sentence,
repeated **69 times on one page**, refused because the marker it names is quoted. None of it was
counted, because a run refused at the door never becomes a miss. That is the same failure shape this
repository keeps meeting: a green report over a record that had changed meaning.

**A quotation is now a hole in a template, exactly as a number is.** `i18n.citar()` takes each
balanced «…» span out and replaces it with `¤`; the prose around it is the segment and translates
once; `i18n.descitar()` puts the span back byte-identical. Not one character inside the guillemets
is ever touched, which is the whole of what the guard existed to protect — gate 44 still asserts
every excerpt, name and edge of the graph is byte-identical in every language, and it is.

**What is still refused is an UNBALANCED guillemet, and the distinction is exact.** Where a
quotation opens in one run and closes inside the markup that follows, the text after « really is
quoted and translating it would misquote a fragment. The one safe shape is a stray that carries no
quoted text with it: a « that is the run's last character, or a » that is its first. That is exactly
what the split around «Independent» produces, which is why those two runs are now translated and the
quotation between them is untouched. The one place a quotation is genuinely split across markup with
quoted text on both sides — the two candidate sentences in the regulator story — stays Portuguese,
and that is the guard working rather than failing.

**Seventeen translations already in the memory were converted mechanically rather than retyped.**
Masking changes a segment's key, so every sentence carrying a quotation became a new segment and its
old translation became an orphan. Applying the same mask to the old translation and checking that the
hole count matches the source's converted 17 segments in three languages with zero mismatches. The
other 15 were written by hand. This is the cost curve the design exists for: a rule change should not
cost a full retranslation.

**The verbatim harvest was missing the field names the DATA actually uses.** `i18n.verbatim()` named
`cargo_listado` and `organizacao_listada` — the ontology's names for those fields — while
`dados/pessoas.json` calls them `papel` and `organizacao`. The consequence was invisible while the
coverage metric could not see unaccented labels, and it is not small: **a hundred-odd listed roles
read verbatim out of a frozen page** («CIO & Co-founder», «Managing Partner») were classified as
Portuguese awaiting translation. Rule 3 says third-party text is linked and never rewritten and rule
4 forbids any characterisation of a named person, so translating a listed role would be inventing
one. `papel`, `organizacao`, `dia`, `tema`, `formato`, `quando` and `correspondeu` are now named
alongside the others — the day a programme declares, the event's own topic, the format it names, and
the words the published lexicon matched are all read verbatim out of somebody else's bytes.
`titulo` is deliberately NOT among them: it holds session titles, which are verbatim, AND this
newsroom's own headings, which are not, and guessing would silence prose that should be translated.

**An `&amp;` was hiding a name from its own verbatim test.** The test ran on the raw run, so
«Gacs Ltd &amp; Gacsym Ventures» matched no name in `dados/` and an organisation stopped being
recognised as an organisation. This is the second time the same entity has found the same class of
bug; the test now runs on the unescaped form as well as the raw one.

**`--relatorio` now prints the list, not just the number.** `dados/i18n/vocabulario.json` documents
itself as extended from that report — «--relatorio lists every run a reader would see in Portuguese
that the memory cannot serve, most frequent first» — and the report printed a table and no list. A
number nobody can act on is the same problem as a number that reads 100% over a Portuguese page. 39
short labels found that way are now declared in the catalogue and translated in all three languages:
`O registo`, `O aviso`, `· fonte:`, `· ficheiro:`, `Ficheiro congelado`, `Papel listado`, the
section names in their definite-article form, and the `· pt.newsroom.sgit.ai` page titles.

**The measurable result: 15 536 substitutions per locale page set, up from 14 153.** 1 383 runs a
reader used to see in Portuguese on an English, French or German page, now in the language the page
claims to be in. All 44 gates green, the browser gate green over 20 pages, and the utility strip
still 1168×33 in both chromes.

**An honest remainder, measured rather than guessed.** `i18n.parece_portugues()` finds Portuguese by
accent or function word, so it cannot see an unaccented label — `O registo`, `Papel listado`. Widening
it to «any run with a letter that is not a name and not a machine fact» was tried during this release
and reported **1 798 occurrences across 154 distinct runs**, which is the true size of what the
current metric cannot see. But it also reported, as Portuguese, the lexicon's published regular
expressions, the ontology's ASCII type names, the graph's reading templates, the back office's
declared English, and names truncated for display with a `· 5×` suffix. Each of those is a rule of
its own to write, and writing seven rules in a hurry inside a release is how a metric starts lying in
the other direction. The widening was reverted, the 39 labels it positively identified were declared
and translated, and the measurement is written down in `redacao/issues/012` so the next session
starts from the number instead of rediscovering it. The coverage figure reads 100% over a denominator
that is honest about accented Portuguese and blind to unaccented labels — and this paragraph is the
disclosure, because a footnote nobody writes is how the last one survived three releases.

**`CLAUDE.md` still says «Everything a reader sees is European Portuguese under AO90».** Three
languages now, on the editor's conversational authorisation, and the file is theirs to amend. The
wording is in `redacao/issues/010`, unchanged and still waiting.
