mirror of
https://github.com/fsolla/teqo.git
synced 2026-11-14 17:43:04 +00:00
118 lines
12 KiB
Markdown
118 lines
12 KiB
Markdown
# 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`) + um `summary` curto, completo e auto-contido quando a superfície de resumo exigir → o builder usa `summary`; sem ele, prefere `answer` e **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 mede `scrollHeight` e **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 todo `slice` do repo além da família C163/C186.
|
||
|
||
### Esboço de fluxo (B)
|
||
|
||
```text
|
||
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 `designer` entra 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 `summary` documentado nos dois arquivos de pesquisa e instruído nas skills `relatorio-cidade` e `dossie-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 `summary` nos 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-cidade` e `dossie-solla-cidade` instruem o researcher a redigir `summary`.
|
||
|
||
## 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 `summary` global em vez de por item.** **Corte neste item:** `summary` por 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 `slice` silencioso 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 `summary` vs só ampliar orçamento?** **Opções:** A) `summary` por 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 #<N> (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-1383`
|
||
- `scripts/lib/cityReportRender.mjs:243-244,470,531,631,872,901,1185`; `scripts/lib/cityReportResearch.mjs:129-138,186`
|
||
- `scripts/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-175`
|
||
- `scripts/lib/dossieCamara.mjs:16,46,128`; `scripts/lib/dossieRender.mjs:477-488`; `scripts/lib/dossieResearch.mjs:211-224,263`
|
||
- `scripts/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)
|