12 KiB
Relatórios e dossiês sem truncamento mecânico — reformular para caber ou ampliar o campo
Status: rascunho Atualizado em: 2026-09-17 Issue: #1136 Priority: P2 Impeccable: B — encaixe nas superfícies já desenhadas (relatório C163, dossiê/boletim C186); sem redesenho Design UI: N/A — superfície inalterada; alvo é o hi-fi já aprovado do C186 (e o do C163) Appetite: ~1–2 dias eng; um outcome verificável — gerar relatório/dossiê com texto longo e não ver nenhum "…", nenhum item sumido sem aviso, com o integral preservado no aprofundamento e a guarda de fit verde Responsável: —
Intenção
Ao gerar um relatório de cidade (C163) ou um dossiê/boletim (C186), informação se perde na última milha: ou o texto é cortado mecanicamente no meio da frase com "…" (C163, via excerpt()), ou itens inteiros somem em silêncio (C186, listas com slice e sem contador). Não é falta de espaço editorial — é o orçamento da superfície aplicado como corte cego. Regra do produto: se uma informação não cabe, o texto deve ser reformulado para caber perdendo o mínimo de informação, ou o campo/orçamento deve ser ampliado — nunca corte mecânico no meio, nunca item sumindo sem aviso. O pesquisador levanta o dado; o artefato não pode descartá-lo.
Persona e fluxo
- Persona / contexto: o gabinete/assessoria prepara material pré-viagem; o researcher (humano ou skill) entrega respostas longas e ricas; o builder compõe a página 1/resumo (C163), o dossiê e o boletim (C186).
- Job principal: ao abrir o PDF, ler a informação completa e confiável — e, se algo não coube no resumo, saber que existe e onde achá-lo, nunca descobrir depois que um trecho foi cortado no meio.
- Fluxo desejado: researcher entrega o integral (
answer/details) + umsummarycurto, completo e auto-contido quando a superfície de resumo exigir → o builder usasummary; sem ele, prefereanswere amplia o campo/orçamento enquanto a guarda de fit permitir → se ainda não couber, a linha aponta o aprofundamento sem reticências → toda lista truncada exibe contador ("e mais N"/"Mostrando X de Y") → o integral segue no aprofundamento → a guarda de fit medescrollHeighte aborta se estourar. - Anti-goals de produto: corte mecânico com "…" em superfície de resumo; item sumindo em silêncio; espremer o layout para caber (a guarda continua fail-closed); redesenhar as superfícies; o builder reescrever conteúdo editorial (quem redige o
summaryé o researcher); varrer todoslicedo repo além da família C163/C186.
Esboço de fluxo (B)
pesquisa (answer/details integral)
├── summary? ──sim──> superfície de resumo (pg1/cartões)
└── não ─> prefere answer ─┤
▼
cabe no orçamento? ──sim──> renderiza
└── não ─> amplia orçamento (guarda permite?) ──> renderiza
└── não ─> linha aponta o aprofundamento SEM "…"
integral sempre preservado no aprofundamento (seção Fontes / páginas extras)
listas: slice → SEMPRE com contador "e mais N" / "Mostrando X de Y"
guarda de fit: scrollHeight > orçamento (+tolerância) → ABORTA (fail-closed)
Design UI (B)
- Design UI: N/A — as superfícies têm design aprovado (relatório C163; dossiê e boletim C186). Este item não redesenha: ajusta conteúdo/orçamento dentro do hi-fi existente, sem componente/estado/layout novo. Se a execução exigir mudança material de layout, o
designerentra e a mudança volta ao humano no PR.
Objetivo e aceite
- Gerar relatório/dossiê/boletim com textos longos e não ver nenhum "…" em superfície de resumo.
- Nenhuma lista truncada sem contador de itens restantes.
- Texto integral sempre disponível no aprofundamento.
- Guarda de fit verde (fail-closed preservado; nunca espremer).
- Contrato
summarydocumentado nos dois arquivos de pesquisa e instruído nas skillsrelatorio-cidadeedossie-solla-cidade. - Guardrails de produto: sem fonte não publica; empenho ≠ pagamento; esfera/abrangência nunca somadas; PII mínima; artefato gitignored; defeso.
Dados (intenção)
- Vou apresentar dados? Sim, superfície neste item — o item decide como o dado já pesquisado é renderizado (orçamento de texto e contadores), nas superfícies impressas C163/C186.
- Decisões desbloqueadas: o leitor decide com base no texto completo (não num fragmento cortado); o gabinete sabe o que ficou de fora do resumo (contador) e onde está o integral; o researcher sabe para qual orçamento redigir o
summary. - Forma: adiada ao plano de implementação — aqui só restrições de produto: proibido "…" na superfície de resumo; contador em toda lista truncada; integral no aprofundamento; guarda de fit fail-closed; sem redesenho.
Dados da decisão (literais)
Corte mecânico com "…" — dono único no C163. excerpt() em scripts/lib/cityReportBlocks.mjs:91-94 (slice(0,max).trimEnd()+'…'). Caps: PAGE_ONE_ANSWER_MAX=90, PAGE_ONE_WHO_MAX=26, PAGE_ONE_RISK_MAX=70, PAGE_ONE_NAMES_MAX=20, PAGE_ONE_INDICATOR_DETAIL_MAX=70 (:64-79); SIGNAL_EXCERPT_MAX=180, SPEECH_SUMMARY_MAX=220, SPEECH_MENTION_MAX=220 (:53-55). Call-sites impressos na página 1: :154-161→:232,236,255,288,292,310,350,382; joinLimited :100-105→:198,248,322; excerpt(indicator.purpose, 70) :368. Integral preservado em buildResearchAnswersTable :1362-1383.
Descarte silencioso no C186. limit = list.slice(0,max) scripts/lib/dossieBlocks.mjs:96 (sem flag de resto) em :181-186 (MAX_ERA_NUMBERS=12), :190 (MAX_ERA_ACTIONS=4), :202-224 (MAX_DELIVERIES_PAGE_ONE=3), :226-233 (MAX_HOOKS_PAGE_ONE=2), :241-244 (MAX_PENDING_PAGE_ONE=4), :247-255 (MAX_REGION_ITEMS=4); único com contador: :333/:338 (MAX_SCOPE_LIST=5, guarda .total). Boletim: scripts/lib/dossieBulletin.mjs:44 (6) + :51 (14) = teto 20, sem contador (dossieBulletinRender.mjs:171-175).
Corte silencioso de caractere sem "…": scripts/lib/dossieCamara.mjs:46 (sumario ?? transcricao).slice(0,280), ITEMS_PER_LIST=20 :16,128; cityReportBlocks.mjs:870 row.body.slice(0,180); :1113 row.summary.slice(0,220); :1097 mentionExcerpt.slice(0,220).
Guarda de fit (não corta — aborta): C163 build-city-report.mjs:155-165 (PAGE_ONE_BUDGET_PX, −8px; aprofundamento não é medido); C186 dossiê build-dossie-solla-cidade.mjs:196-227 e boletim :241-249 (+10px). .sheet { height:297mm; overflow:hidden } (dossieRender.mjs:477-488, dossieBulletinRender.mjs:31-43).
Contrato do resumo (nova regra, literal): cada item de pesquisa passa a aceitar summary — curto, completo e auto-contido, redigido para caber no orçamento da superfície de resumo. Superfícies de resumo usam summary; aprofundamento continua com o integral (answer/details). Sem summary, prefere answer e amplia o orçamento enquanto a guarda permitir — "…" proibido; no limite, a linha aponta o aprofundamento sem reticências. Nenhum item some em silêncio (contador sempre). Guarda de fit fail-closed.
Contratos hoje: cityReportResearch.mjs:129-138,186 e dossieResearch.mjs:211-224,263 aceitam answer/details; news[].summary é validado e nunca renderizado; não há summary em items[].
Testes a atualizar: tests/unit/cityReportBlocks.unit.spec.ts:702,752,780; tests/unit/cityReportRender.unit.spec.ts:127,166; tests/unit/dossieBlocks.unit.spec.ts:155; tests/unit/dossieBulletin.unit.spec.ts:27,60.
Direção no codebase (hipótese)
- Dono único de orçamento/composição de texto substitui o
excerpt()do C163, reusado por C163 + C186 (não gemar caminho paralelo). - Contrato
summarynos dois arquivos de pesquisa (cityReportResearch.mjs,dossieResearch.mjs). - Renderers C163/C186 preferem
summary; integral permanece no aprofundamento. - Contadores "e mais N"/"Mostrando X de Y" em todas as listas hoje silenciosas (dossiê/boletim;
dossieCamara.mjs). - Testes unit dos caps revisados e do novo contrato; skills
relatorio-cidadeedossie-solla-cidadeinstruem o researcher a redigirsummary.
Dependências
- Soft com C187 (dossiê por instituição) — o novo item deve nascer sem truncamento; este item conserta o dono que o C187 reusa. Sem bloqueio.
- Nenhuma dura.
Fora de escopo
- Redesenhar as superfícies (o design aprovado do C186/C163 permanece).
- Persistir dado novo, schema ou migration; alterar contratos públicos/URL.
- Mudar o conteúdo editorial além do que cabe — o
summaryé redigido pelo researcher. build-solla-ceuci-salvador-report.mjs(C157): só se for trivial e no mesmo dono; senão, item sucessor.
Rabbit holes de produto
- "Fazer caber" reescrevendo no builder. Se alguém "só completar": o builder vira redator. Corte neste item: o builder não redige; sem
summary, aponta o aprofundamento. - Um
summaryglobal em vez de por item. Corte neste item:summarypor item, auto-contido por superfície. - Ampliação de orçamento vira licença para a página crescer. Corte neste item: a guarda de fit fail-closed é o teto.
- Varrer todo
slicesilencioso do repo. Corte neste item: só a família C163/C186 (C157 como sucessor, se não for trivial). - Confundir "e mais N" (lista) com "…" (frase). Corte neste item: são dois defeitos distintos, com remediações distintas — tratar ambos, sem trocar um pelo outro.
Questões em aberto (produto)
- Campo
summaryvs só ampliar orçamento? Opções: A)summarypor item + ampliação como fallback | B) só ampliar orçamento. Recomendação: A — resolve na origem e dá ao researcher controle editorial. (assumido — validar) - "…" sempre proibido ou só no aprofundamento? Opções: A) proibir nas superfícies de resumo, manter no aprofundamento | B) proibir em tudo. Recomendação: A — o aprofundamento já carrega o integral. (assumido)
- Cobrir C157 agora ou sucessor? Opções: A) incluir | B) sucessor. Recomendação: B — C157 não compartilha o dono reusado por C163/C186. (assumido)
- Prioridade P1 vs P2? Opções: A) P1 (perda de informação visível) | B) P2. Recomendação: B — reavaliar para P1 se o C187 entrar em produção imediatamente. (assumido)
Referências
- GitHub Issue # (após
pnpm agent:register) scripts/lib/cityReportBlocks.mjs:53-55,64-79,91-94,100-105,154-161,163-177,359-378,870,1097,1113,1362-1383scripts/lib/cityReportRender.mjs:243-244,470,531,631,872,901,1185;scripts/lib/cityReportResearch.mjs:129-138,186scripts/lib/dossieBlocks.mjs:96,181-186,190,202-233,241-255,333,338;scripts/lib/dossieBulletin.mjs:44,47-48,51;scripts/lib/dossieBulletinRender.mjs:171-175scripts/lib/dossieCamara.mjs:16,46,128;scripts/lib/dossieRender.mjs:477-488;scripts/lib/dossieResearch.mjs:211-224,263scripts/build-city-report.mjs:155-165;scripts/build-dossie-solla-cidade.mjs:196-227,241-249- Testes:
tests/unit/cityReportBlocks.unit.spec.ts:702,752,780;tests/unit/cityReportRender.unit.spec.ts:127,166;tests/unit/dossieBlocks.unit.spec.ts:155;tests/unit/dossieBulletin.unit.spec.ts:27,60 - Skills:
.agents/skills/relatorio-cidade/SKILL.md,.agents/skills/dossie-solla-cidade/SKILL.md;AGENTS.md(edite o dono, não gema um irmão)