**The chat's tools were fetching from the wrong place on every page but the front one.** Reported
by the editor with a screenshot: asking «what is the article I'm reading now?» came back with
`listar_artigos falhou: articles.json respondeu 404`. The engine built the path to `/api/v1/` by
counting the segments of `location.pathname`, and it was wrong twice over in a way that hid
itself — the count was short by one for a directory URL (`/artigos/2026/09/14/<slug>/` needs five
`../` and got four), and the result was then joined to a prefix that began with a slash, so the
whole address collapsed to `/artigos//api/v1/`. On the front page `raiz()` returns nothing and the
absolute prefix saved it, which is why it looked like it worked.

**Counting was the mistake, not the arithmetic.** `assets/conversa.js` sits at
`<root>/assets/conversa.js`, so one step up from its own URL is the site root — at any depth, under
any prefix, with no rule to keep in step with the page tree. It is the mechanism `SgComponent`
already uses to find its own markup (`static jsUrl = import.meta.url`), and the reason a component
can be moved without being told where it went. A 404 now also names the address actually requested,
not just the path, because the old message sent you looking at a file that was there all along.

**The second half of the same report: an id that was quietly repaired into a wrong one.** The model
called `ler_artigo` with `2026/09/14/dois-nomes-para-os-mesmos-palcos`; the engine stripped the
characters an id may not have and fetched `20260914dois-nomes-para-os-mesmos-palcos`, a path nobody
wrote. **Silently repairing an argument turns a wrong question into a wrong answer** — on this site
the one failure mode that does not look broken. It now refuses, and says what an id is, which tool
hands them out, and gives a real example. Each `{id}` tool carries its own example in the schema,
and `ler_artigo` states outright that the folder is dated but the id is not.

**A gate that asks questions.** The chat's tools are only exercised when somebody asks something,
and no gate asks anything — so the browser check now calls every listing tool for real, from the
deepest page on this site and from the shallowest, and reads one article by an id the listing
itself handed out. Both paths are needed: the article page is where the arithmetic broke, and the
front page is where the old code accidentally worked, so a deep-only check would have passed a
half-fix.

**Gate 34's scope stopped one directory short of the code that mattered.** It covered
`assets/components/` and missed the four scripts directly above them — the bridge, the observer,
the graph viewer and the chat engine, about 240 comment lines, two of them about what leaves the
reader's browser. All four are now in English and in scope, vendored third-party code excepted
because rewriting it to our taste would break the reason it is vendored at all.

**And the gates themselves now fail in English.** Fifty-eight failure messages in
`build/gates_artigos.py` were Portuguese while the summary line above them was English. A gate
message in a terminal is read by whoever operates this newsroom, so it follows the same rule as the
rest of the code; values quoted out of the files — a state, a section, a name — stay exactly as the
file has them, because those are data.

*Left for the migration release, recorded here rather than fixed quietly: the article state
`superseded` is an English id in an otherwise Portuguese vocabulary. The label a reader sees is
«Substituído»; only the id is out of place, and ids are what that release is about.*

*Also: `admin/versions.json` carried a hand-maintained `contagem` that drifted the first time two
sessions each added a note. It is now counted from the list, and rewritten when it disagrees.*

*And a merge lost something quietly, which is worth recording because nothing failed.* The design
review's stylesheet arrived as a wholesale rewrite of `assets/site.css`; git auto-merged it without
a conflict, and the four rules that give `<pt-chat>` its column went with it. The panel still
opened and simply lay across the article again — the same symptom as the `[hidden]` bug two
releases ago, from an entirely different cause. They are back, with a comment saying so.
