diff --git a/.agents/skills/relatorio-cidade/SKILL.md b/.agents/skills/relatorio-cidade/SKILL.md
index 08c05791..1ebb43b0 100644
--- a/.agents/skills/relatorio-cidade/SKILL.md
+++ b/.agents/skills/relatorio-cidade/SKILL.md
@@ -180,10 +180,11 @@ cacheado em `data/relatorios-cidade/.emendas.json` para replay.
(passagem que cita a cidade ou, se o nome não aparece nos trechos, a marcação
do acervo com o nº de municípios), mais **Vídeo** (YouTube no trecho da fala
— `youtubeExcerptStartSeconds` = época do trecho (`excerptTMs`) − início da
- sessão, com folga de 20s no link; o `speechAt` da API é o horário do slot,
- não o início real; fallback para o VOD da Câmara, que é o clipe do próprio
- trecho) e **Transcrição** (PDF do Diário) quando existirem ·
- `11. Notícias e imprensa` ·
+ sessão, calibrado contra o vídeo real: o da sessão de 13/03/2018 começa ~37s
+ depois do `eventStartAt`, então 645s viram `t=608s` (`YOUTUBE_VIDEO_OFFSET_SECONDS`);
+ o `speechAt` da API é o horário do slot, não o início real; fallback para o
+ VOD da Câmara, que é o clipe do próprio trecho) e **Transcrição** (PDF do
+ Diário) quando existirem · `11. Notícias e imprensa` ·
`12. Panorama regional` · `13. Abordagem sugerida (personas)` · `14. Fontes e
limites`.
- **Links clicáveis:** todo URL no PDF é um link (``): células de
diff --git a/docs/changelog/2026-09-15-c163-falas-calibracao-video.md b/docs/changelog/2026-09-15-c163-falas-calibracao-video.md
new file mode 100644
index 00000000..e2c2ecd7
--- /dev/null
+++ b/docs/changelog/2026-09-15-c163-falas-calibracao-video.md
@@ -0,0 +1 @@
+**C163 — calibração do link do vídeo: t=608s (2026-09-15):** verificação no vídeo real (`youtube.com/live/2cX_gKkJH7Q?t=608`) mostrou que a sessão de 13/03/2018 começa ~37s depois do `eventStartAt`; o trecho da Câmara (645s no relógio da sessão) toca em 608s. O builder trocou a folga genérica de 20s por `YOUTUBE_VIDEO_OFFSET_SECONDS = 37`, calibrado contra essa sessão, e o link da fala 641 ficou `youtube.com/watch?v=2cX_gKkJH7Q&t=608s`. Unit 3118/3118, `tsc`/eslint verdes; PDF regerado.
diff --git a/scripts/lib/cityReportBlocks.mjs b/scripts/lib/cityReportBlocks.mjs
index 9cd88a82..cb4dae5e 100644
--- a/scripts/lib/cityReportBlocks.mjs
+++ b/scripts/lib/cityReportBlocks.mjs
@@ -854,12 +854,12 @@ const buildTransportSection = ({ research }) =>
/**
* YouTube link starts at the Câmara excerpt of the speech (`excerptTMs` −
- * session start): `speechAt` is the API slot clock, not when the deputy
- * actually speaks (for speech 641 the previous speaker is still on at
- * `speechAt`). A short lead-in keeps the link from starting already inside the
- * speech when the session video drifts a few seconds.
+ * session start), calibrated by the live video: the 2018-03-13 session video
+ * starts ~37s after `eventStartAt`, so the excerpt at 645s plays at 608s
+ * (`youtube.com/live/2cX_gKkJH7Q?t=608`, checked in the browser). `speechAt` is
+ * the API slot clock, not when the deputy speaks.
*/
-const YOUTUBE_LEAD_IN_SECONDS = 20
+const YOUTUBE_VIDEO_OFFSET_SECONDS = 37
const withYoutubeTimestamp = (url, offsetSeconds) => {
if (!url) return null
@@ -870,7 +870,7 @@ const withYoutubeTimestamp = (url, offsetSeconds) => {
const youtubeStartSeconds = (row) =>
Number.isFinite(row.youtubeExcerptStartSeconds)
- ? Math.max(0, Math.floor(row.youtubeExcerptStartSeconds) - YOUTUBE_LEAD_IN_SECONDS)
+ ? Math.max(0, Math.floor(row.youtubeExcerptStartSeconds) - YOUTUBE_VIDEO_OFFSET_SECONDS)
: null
const buildSpeechesSection = ({ snapshot }) => {
diff --git a/tests/unit/cityReportBlocks.unit.spec.ts b/tests/unit/cityReportBlocks.unit.spec.ts
index 333921c5..4ba153b9 100644
--- a/tests/unit/cityReportBlocks.unit.spec.ts
+++ b/tests/unit/cityReportBlocks.unit.spec.ts
@@ -445,7 +445,7 @@ describe('buildCityReport', () => {
expect(falas.columns!.find((column) => column.key === 'mention')!.width).toBe(27)
expect(rows[0].description).toBe('Resumo da fala')
expect(rows[0].mention).toContain('cita Feira de Santana')
- expect(rows[0].video).toBe('https://youtube.test/video?t=625s')
+ expect(rows[0].video).toBe('https://youtube.test/video?t=608s')
expect(rows[0].transcript).toBe('https://camara.test/discurso')
expect(rows[1].description).toBe('Saúde indígena na Bahia')
expect(rows[1].mention).toContain('nome não localizado nos trechos')