O briefing de capacitação passa a renderizar o pedido dual (deputado federal 1313 e, no 2º turno, Lula 13) e a exigir ao menos uma pergunta de 2º turno no Q&A; dossiê e boletim seguem sem CTA (prova material do argumento, não peça de rua). Registra o changelog da entrega.
15 KiB
| name | description |
|---|---|
| briefing-capacitacao-solla | Gera o Briefing de capacitação Solla 1313 por recorte (cidade · instituição · tema): PDF A4 de até 4 páginas + companion .md, derivado do dossiê já pesquisado (sem segunda pesquisa factual), todo de recorte — princípios/crenças e defesas de Solla com fonte, fatos-âncora e o pedido literal do voto (1313 e, no 2º turno, Lula 13), e perguntas prováveis × melhores respostas dos dois lados; aceita um recorte ou um lote separado por vírgula. |
Briefing de capacitação Solla 1313 (C210)
Entrega, por recorte (cidade · instituição · tema), um PDF A4 de até 4
páginas + companion .md para quem vai pedir o voto 1313 no recorte.
Depois do replanejamento (2026-09-23), o briefing é todo do recorte — não tem
capa, manual genérico, roteiro de passos, anti-padrões nem limites:
- O que Solla defende — princípios/crenças do recorte (abertura) + posições com lastro (fonte e data);
- O essencial do recorte — fatos-âncora com fase junto ao valor e o pedido literal do voto (1313 e, no 2º turno, Lula 13) + uma linha de plano;
- Perguntas prováveis × melhores respostas (1/2 e 2/2) — as perguntas reais do recorte, metade do documento, com os dois lados.
É insumo interno de capacitação: rótulo literal
Insumo interno de capacitação — não publicar em todas as folhas, sem CTA
público, sem marca publicável, artefato gitignored.
Ele deriva do dossiê daquele recorte — nunca faz segunda pesquisa factual:
os fatos vêm do ledger bulletinFacts (só item com fonte) e a lacuna é
declarada, não preenchida. É o 3º entregável da família
dossie-solla-{cidade,instituicao,tema} (dossiê + boletim + briefing na mesma
invocação) e também roda sozinho. O layout vem do design hi-fi aprovado
docs/plans/briefing-capacitacao-solla-ui-design.html — o port é
classe-a-classe, sem improviso visual.
Missão do 2º turno (Lula × Flávio — 25/10/2026)
O briefing é o insumo de quem pede voto na rua: desde 08/10/2026 o pedido é
dual — o voto 1313 (Solla) e, no 2º turno, o voto 13 (Lula). O pedido é
literal do renderer (não se reescreve no JSON); o plan é a única linha em
que o autor diz como combinar os dois. Os números do 2º turno (Lula × Flávio,
X₁/X₂) não entram neste contrato: vivem no relatório de cidade
(relatorio-cidade, seção "2º turno no município"), e cenário/estimativa seguem
proibidos aqui.
Quando usar
- A coordenação pede "o briefing de " para quem vai panfletar/pedir voto — ou vários numa invocação.
- O fluxo do dossiê (
/dossie-solla-cidade,/dossie-solla-instituicao,/dossie-solla-tema) entrega o briefing junto do dossiê e do boletim, com a mesma skill/build — nunca um segundo pipeline. - Quem executa são o orquestrador (agente principal) + um sub-agente
autor por recorte + o script
build-dossie-solla-briefing.mjs(local, offline). O detalhe está em "Pipeline (etapas)".
Lote (recortes)
A invocação aceita um recorte ou vários, separados por vírgula, cada token prefixado pelo recorte:
/briefing-capacitacao-solla cidade:Miguel Calmon # N=1
/briefing-capacitacao-solla cidade:Ilheus, instituicao:UFBA, tema:Saude # lote misto
Parsing (orquestrador, antes de qualquer redação):
- separa por
,; aplicatrim; descarta vazio; o token é<recorte>:<valor>com recorte emcidade | instituicao | tema; - cidade resolve como na skill irmã (
isMunicipalitySlug/resolveMunicipalityName→municipalityCatalogEntriesForCity;Salvadoré ambíguo = peça o slug da zonasalvador-ze-N); - instituicao resolve no catálogo (
isInstitutionSlug/resolveInstitutionName→src/lib/institutionCatalog.ts; ambíguo falha fechado); - tema resolve na taxonomia fechada (
resolveSpeechTopicsobreSPEECH_TOPICSdesrc/lib/speechFacets.ts; aceita valorsaudeou labelSaúde); - dedupe após a resolução, preservando a ordem; token inválido/ambíguo ou sem prefixo vira falha isolada com o motivo no summary final — nunca aborta o lote nem inventa slug.
Um recorte = um briefing (PDF + MD); sem índice/PDF agregado. Falha de um recorte não cancela os demais (sucesso parcial explícito).
Pipeline (etapas)
- Orquestrador (agente principal). Parseia a lista (seção "Lote") e resolve
os recortes nos catálogos das skills irmãs — sem pesquisa web aqui. Nunca
retém o corpo de um
research.json: só os recibos. - Autor (sub-agente, 1 por recorte).
.opencode/agent/briefing-capacitacao-solla.md— lê osdata/dossie-solla-<recorte>/<slug>.{a,b,c}.research.jsone (quando houver) o<slug>.narrative.json, redige o<slug>.briefing.jsonno contrato abaixo somente a partir dos itens com fonte, e devolve só o recibo (seção "Recibo do autor"). Não faz pesquisa nova, não edita research, não roda build/ssh, não commita. - Auditoria de citações (orquestrador). Confere citação por citação (nome,
data, valor, órgão, alcance) contra os
research.json; todo item ancorado aponta umfactIdreal que lastreia a nota (o ledger resolve o id pelo primeiro item daquele id) e todo texto sem lastro é corrigido ou removido. Fato novo não entra: viragapReason. - Build local (por recorte), offline:
NODE_OPTIONS="--no-deprecation --import=tsx/esm" node scripts/build-dossie-solla-briefing.mjs \ --unit=municipality \ --snapshot=data/dossie-solla-cidade/<slug>.snapshot.json \ --research-dir=data/dossie-solla-cidade \ --out-dir=docs/research/dossie-solla-cidade--unit=institution|themepara os outros recortes (defaultmunicipality). O build valida obriefing.jsonfechado (âncora que não resolve em fato com fonte = erro; chave de cenário/staff-only = erro), renderiza as 4 folhas fixas do recorte (defesas → essencial + pedido → qa 1/2 → qa 2/2), mede cada folha e emite 1 PDF com a guarda de teto de páginas (emitHtmlSinglePdf,maxPages=4). Saídas:docs/research/dossie-solla-<recorte>/<slug>-<YYYY-MM-DD>-briefing.pdf+-briefing.md; intermediários gitignored emdata/dossie-solla-<recorte>/. - Summary final. Uma linha por entrada, na ordem da lista:
entrada · status (ok|failed) · briefing (quando ok) · motivo (quando falha).
O teto de 4 páginas é rígido: se uma folha estourar, o build corta por
prioridade (qa até o mínimo de 4 com os dois lados → defesas até esvaziar)
e declara o resto na folha ("e mais N no briefing completo (.md)"); o
companion .md carrega tudo. O essencial (fatos-âncora), o pedido e a
identificação nunca são cortados; se nem o mínimo couber, o build falha
fechado apontando a lista a encurtar.
Contrato do <slug>.briefing.json
Escrito pelo autor, validado pelo build (scripts/lib/briefingContent.mjs):
{
"unitId": "municipality", // municipality | institution | theme
"municipalitySlug": "miguel-calmon", // chave = slugField da unidade (institutionSlug | themeSlug)
"generatedAt": "2026-09-23T12:00:00.000Z", // obrigatório
"subtitle": "Piemonte da Diamantina · consulta antes e durante o contato", // opcional
"lede": "≤380 chars — princípios e crenças do recorte (abre a folha 1)",
"defenses": [ // posições com lastro (folha 1); [] = linha de lacuna
{ "factId": "era_b_defesas", "sourceUrl": "https://…", "title": "≤120", "note": "≤200" }
],
"essential": [ // ≥3; fatos-âncora (folha 2); cada item: factId XOR gapReason
{ "factId": "era_b_equipamentos", "sourceUrl": "https://…", "title": "≤120", "note": "≤200" },
{ "gapReason": "sem fala própria localizada", "title": "…", "note": "…" }
],
"plan": "≤220 chars — uma linha de plano de voto/compromisso nomeado (pode dizer como combinar o 1313 com o voto 13 no 2º turno)", // obrigatório
"qa": [ // ≥4, com ≥1 "direita" e ≥1 "esquerda"
{ "side": "direita|esquerda|entrega", "question": "≤180",
"acknowledge": "≤200", "answer": "≤520", "close": "≤200",
"factId": "era_b_sesab", "sourceUrl": "https://…" /* XOR */ "gapReason": "sem registro localizado" }
]
}
Regras duras:
unitIde o slug têm de casar com o recorte do build (outro recorte = erro);- cada item de
defenses/essential/qaexige exatamente um defactId | gapReason;factIdtem de resolver num fato do ledger comsourceUrl— sem fonte, o item não entra; - o id de checklist se repete entre itens do research e o ledger resolve o
factIdpuro pelo primeiro item daquele id; para ancorar outro item, o autor copia osourceUrldo item do research no camposourceUrldo âncora (o parfactId+sourceUrlprecisa bater — par errado falha fechado); qacobre os dois lados (≥1direitae ≥1esquerda);entregaé opcional; desde 08/10/2026, inclua ao menos uma pergunta de 2º turno (por que votar em Lula; o que está em jogo para a cidade) — ancorada no mesmo ledger, sem cenário nem número de pesquisa;- proibido qualquer chave de cenário/estimativa/staff-only
(
estimatedVotes,scenario,projection,polls, …) — o briefing não tem campo numérico; valor/fase vêm do fato-âncora no render; - caps de texto acima do limite são aviso (o autor encurta); quem falha fechado é a guarda de fit/páginas;
- a folha 1 abre com
lede(princípios/crenças) e a listadefenses— o autor deve trazer 6–10 defesas para encher a folha; a folha 3–4 acomoda 8–10 perguntas (o build divide a lista ao meio).
O pedido é literal do renderer (não reescreva no JSON): "Posso contar com
você? Para deputado federal, vote 1313, Jorge Solla. E no 2º turno, vote 13, Lula." — o plan é a única linha de orientação que o autor escreve
(ex.: onde/como combinar o pedido municipal com o voto em Lula).
Recibo do autor
Só este recibo curto (≤ ~15 linhas) volta ao orquestrador — nunca o corpo do JSON:
{
"recorte": "cidade",
"slug": "miguel-calmon",
"status": "ok", // ou "failed"
"briefingPath": "data/dossie-solla-cidade/miguel-calmon.briefing.json",
"essentialCount": 5,
"defensesCount": 8,
"qaCount": 9,
"sides": ["direita", "esquerda", "entrega"],
"anchoredFactIds": ["era_b_equipamentos", "era_b_programas", "era_c_atuacao"],
"gapCount": 3, // itens com gapReason + lacunas do recorte
"failureReason": "…" // opcional (só quando status = failed)
}
status: "failed" não escreve arquivo parcial; o orquestrador agrega o motivo
no summary final. Arquivo ausente = o build falha com o ponteiro para esta
skill (não há fallback determinístico: o briefing é redação, não consolidação).
Conteúdo do briefing (4 folhas fixas, todas do recorte)
- Folha 1 — O que Solla defende (
data-page="defesas"): princípios/crenças do recorte (olede) e as posições (defenses) com título, leitura efonte · data. Sem registro = linha de lacuna, nunca posição genérica. - Folha 2 — O essencial do recorte + O pedido (
data-page="essencial"): fatos-âncora com fase junto ao valor e fonte (sem trajetória de formação) e o bloco do pedido com a frase literal + a linha deplan. - Folha 3 — Perguntas prováveis × melhores respostas (1/2) (
data-page="qa"): régua curta (reconhecer → fato com fonte → fechar no pedido) e a primeira metade do Q&A (pergunta + reconhecer/fato/fechar), dois lados. - Folha 4 — Perguntas prováveis × melhores respostas (2/2)
(
data-page="qa-2"): continuação com a segunda metade do Q&A e o "e mais N" quando houver corte.
Fora do briefing (replanejamento 2026-09-23): capa/objetivo, trajetória, roteiro de passos, justificativa científica, "o que evitar", "o que conferir", "se você não souber" e "limites e defeso" — o rótulo interno em todas as folhas já carrega o aviso de insumo.
Guardrails de produto (não negociáveis)
- Rótulo literal
Insumo interno de capacitação — não publicarem todas as folhas; sem CTA público, sem marca de campanha, sem peça publicável. - Teto rígido de 4 páginas A4: corte por prioridade declarada, resto sempre
contado na folha e completo no
.md; nenhuma folha é cortada em silêncio (.sheet{overflow:hidden}esconde o corte — as guardas de contagem e de altura falham fechado). - Sem segunda pesquisa factual: só fatos do dossiê; âncora obrigatória com fonte; lacuna explícita em vez de inferência.
- Sem cenário eleitoral/estimativa/staff-only (nada de
estimatedVotes, projeção, pesquisa); o briefing não promete efeito. - Pedido dual literal: a folha "O pedido" renderiza 1313 + Lula 13 (2º turno) — não é campo do JSON; números de 2º turno continuam fora do briefing (vivem no relatório de cidade).
- Empenho ≠ pagamento; esfera explícita nunca somada; leitura relativa (nunca % estadual absoluto); PII mínima (telefone/e-mail nunca entram).
- Voz com dono único: reusa
.opencode/skills/solla-comunicacao/SKILL.md+referencia/tom-e-exemplos.md(rebates e fórmula de resposta a crítica) — não gema tom. - Falha isolada por recorte não cancela o lote (sucesso parcial).
- Artefato gitignored (repo público): PDF/MD/JSON nunca são commitados.
- Sem schema/migration/DB write/rota — o build é offline (JSON + Chromium).
Troubleshooting
briefing.jsonausente: rode a etapa do autor (sub-agente) e repita; o build não inventa redação.factIdnão resolve em fato com fonte: o item não existe no dossiê ou está sem fonte — troque por umfactIdreal ou declaregapReason; nunca "aproxime" o texto.- Folha estourou: o build corta por prioridade e declara o resto; se a mensagem disser que nem o mínimo cabe, encurte as listas (Q&A/defesas), não o layout.
unitId/slug de outro recorte: o build recusa o par — pare e regenere obriefing.jsonpara o recorte certo.- Sem C209 (defesas):
defenses: []é válido e imprime a linha de lacuna; não complete por memória. - Cenário/staff-only no JSON: o build falha com a chave no erro — remova-a; cenário eleitoral é de outro fluxo (C163), não do briefing.
- Chromium: vem do
@playwright/test; se faltar binário,pnpm exec playwright install chromium.
Referências
- Intenção:
docs/plans/briefing-capacitacao-solla.md; impl:docs/plans/briefing-capacitacao-solla-impl.md. - Design hi-fi (fonte de verdade do port):
docs/plans/briefing-capacitacao-solla-ui-design.html. - Scripts:
scripts/build-dossie-solla-briefing.mjs,scripts/lib/briefingContent.mjs(contrato/shed),scripts/lib/briefingRender.mjs(4 folhas +.md),scripts/lib/buildPdf.mjs(emitHtmlSinglePdf/guarda de páginas),scripts/lib/dossieBlocks.mjs(bulletinFacts),scripts/lib/dossieUnit.mjs. - Skills irmãs (dossiê + boletim):
.agents/skills/dossie-solla-cidade/SKILL.md,.agents/skills/dossie-solla-instituicao/SKILL.md,.agents/skills/dossie-solla-tema/SKILL.md. - Voz/rebates:
.opencode/skills/solla-comunicacao/SKILL.md,.opencode/skills/solla-comunicacao/referencia/tom-e-exemplos.md.