From 0832557e739dbac94bfce9a87caabc118c7b4c21 Mon Sep 17 00:00:00 2001 From: Francisco Solla Date: Thu, 22 Oct 2026 00:22:15 -0300 Subject: [PATCH] =?UTF-8?q?docs(plans):=20registra=20o=20follow-up=20do=20?= =?UTF-8?q?JSON-LD=20da=20peti=C3=A7=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Débito da S48 (#1443): a página de petição serializa o JSON-LD sem escapar '<', enquanto o artigo já escapa. A Issue #1447 fecha o escopo com um helper único em src/utilities/seo.ts usado nas duas páginas. --- docs/plans/json-ld-escape-peticao-impl.md | 56 +++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 docs/plans/json-ld-escape-peticao-impl.md diff --git a/docs/plans/json-ld-escape-peticao-impl.md b/docs/plans/json-ld-escape-peticao-impl.md new file mode 100644 index 00000000..60f2edde --- /dev/null +++ b/docs/plans/json-ld-escape-peticao-impl.md @@ -0,0 +1,56 @@ +# Impl: S48-FOLLOWUP — escape de `<` no JSON-LD da página de petição + +Status: aprovado +Atualizado em: 2026-10-22 +Issue: S48-FOLLOWUP-JSONLD +Intenção: débito registrado na entrega da Issue #1443 (`docs/plans/abaixo-assinado-pl-5594-2026-impl.md`, D6) +Appetite: ~1h eng — correção pontual de paridade de segurança, sem mudança de shape + +## Leitura do débito + +- **Outcome:** o JSON-LD das páginas públicas nunca é quebrado por um valor de conteúdo que contenha ``; a página de petição passa a ter a mesma proteção que a página de artigo. +- **O que NÃO negociar:** o shape do JSON-LD (`Article`), a URL canônica e o HTML renderizado não mudam; conteúdo continua admin-only; sem schema/migration. +- **O que reavaliar:** o artigo repete a serialização inline — a correção deve extrair o dono do concern em vez de criar uma segunda cópia. + +## Abordagem recomendada + +**Opções:** A) repetir `JSON.stringify(jsonLd).replace(/` — um sanitizador amplo seria cerimônia sem volatilidade. + +### Componentes / mudanças + +- **`serializeJsonLd`** (`src/utilities/seo.ts`): `JSON.stringify(value).replace(/`. +- **Duas páginas públicas**: trocar o `JSON.stringify` inline pelo helper; nenhuma mudança de shape. +- **Teste**: unit do helper (`` vira `\u003c/script>`, strings normais intactas, JSON continua parseável) e pin de que as duas páginas usam o helper (source-level, como o pin da copy da petição). +- **Migration:** nenhuma. +- **UI:** Impeccable A — sem UI nova; nenhum trigger do `designer`. + +## Fases verificáveis + +1. **Helper + adoção** — extrair e usar nas duas páginas. +2. **Testes** — unit do helper + pin das páginas; `pnpm test:unit`. +3. **Gates** — `pnpm gate:fast`; entrega com `pnpm push`. + +## Rabbit holes / Não escopo + +- Não criar sanitizador genérico, não escapar `>`/`&` por reflexo, não mudar o `@type`/campos do JSON-LD. +- Não tocar em canonical/OG/metadata; não criar rota/endpoint. + +## Riscos e mitigação + +- **Quebrar o JSON-LD** (escape errado): o unit test faz `JSON.parse` do resultado e compara o objeto; a página continua renderizando o script. +- **Divergência futura**: o helper único + pin source-level impede uma terceira cópia inline. + +## Aceite de engenharia + +- [ ] `serializeJsonLd` é o único caminho de serialização JSON-LD nas páginas públicas. +- [ ] `` em título/subtítulo não fecha o script; JSON permanece válido. +- [ ] Sem schema/migration/URL nova; unit verde e `pnpm gate:fast` limpo. +- [ ] Invariantes AGENTS/engineering-standards preservados (sem PII em log, access inalterado). + +## Self-score decision-quality + +5/5 — decisão cara (onde mora a serialização) tem rejeitadas; appetite de 1h; rabbit holes nomeados; depth check reusa o dono `src/utilities/seo.ts` em vez de twinar; o outcome original da S48 não é reescrito.