# F4.I1.T5 — Revisar TipTap × alternativas (licença/dado vivo) — ADR-001/002

| Campo | Valor |
|---|---|
| **Fase** | F4 — Produto & CMS |
| **Issue** | F4.I1 — CMS próprio e editor (plano 12) |
| **kd task** | `task_013cirxt` (`closed`) |
| **Âncora** | `wiki/implementation/04-produto-cms.md` |
| **Status da revisão** | 🔧 com correções |

## O que foi implementado

- 41 pacotes TipTap/ProseMirror, todos MIT; AST JSON **headless** (dado vivo, sem HTML rígido).
- Alternativas descartadas (Lexical, Quill, Editor.js, TinyMCE, CKEditor GPL, BlockNote MPL…); decisão `decision_011houxu`.

## Arquivos para revisar

- `src/services/RichText/README.md`
- `package.json`
- `tools/assets-licenses-check.php`
- `wiki/adr/ADR-028-editor-rico-tiptap.md`

## Pontos de revisão

### PHP 8.4
- [ ] `declare(strict_types=1)`; tipos nativos (union/enum/`readonly`); sem `mixed` desnecessário.
- [ ] Dependências **injetadas** (nenhum `new`/`app()`/`resolve()` no corpo); sem traits/abstract/generics.
- [ ] `match` em vez de cadeias de `if`; `?->`/`??`; sem código morto; PHPStan `max` limpo.

### Laravel 12
- [ ] Nativo primeiro (Eloquent casts/scopes, `FormRequest`, `Gate`, scheduler, events) — sem reimplementar.
- [ ] Sem closure em rota; resources/rotas nomeadas; `config()` só lê, `env()` só em `config/`.
- [ ] Migração **idempotente**; `down()` → `backup_*` (nunca `DROP`); sem `orderBy` cru quando `latest/oldest` serve.

### HTML semântico + a11y (eMAG/WCAG 2.2 AA)
- [ ] Um `<main>`, headings em nível correto, landmarks; só ARIA quando necessário.
- [ ] Alvos ≥ 24 px (≥ 44 px em ponteiro grosso); foco visível; rótulos em todos os campos; contraste (axe).
- [ ] Funciona **sem JS**; `sniffCSS` sem `fail`/`warn` fora do ledger.

### CSS moderno
- [ ] `oklch`, `clamp`, `rem`/`fr`/`dvh`/`%`; `@layer` (a11y por último); `@property`; subgrid com fallback.
- [ ] Sem `!important`, sem `style="…"` inline, sem hex/rgb (exceto justificado); sem CDN.

### Decisões do projeto (ADRs)
- [ ] Respeita a ADR do escopo (ver cabeçalho) e não escapa das demais (001, 002, 004, 013, 015…).
- [ ] Determinismo: relógio/id injetados, ordem explícita, dados idempotentes (ADR-001).

### i18n (ADR-012)
- [ ] Nenhuma string visível fixa; 4 locales com paridade de chaves; `route()`/`localized_url()` (nunca path literal).

### Observabilidade/segurança/testes
- [ ] Span + `log_event('{module}.{action}')` com atributos `scalar|null`, **sem PII** (ADR-024).
- [ ] Teste que falha sem a mudança (vermelho→verde) + evidência no `kd`; `make quality` 2×.

### Específicos desta task

- [ ] Nenhuma dependência copyleft forte; bundle só no CMS.
- [ ] O AST não guarda HTML/CSS (ADR-017).

## Comandos úteis

```bash
make quality            # lint + PHPStan max + gates + testes
make e2e                # Playwright + axe (se a task toca UI)
make check-boundaries   # fronteiras core/services/layout/modules
```

---

> Revisar contra `AGENTS.md`, `wiki/adr/` e o plano citado. Registrar achados no `kd` (`kd write --anchor`) e, se houver correção, teste de regressão.

## Notas da revisão

| Data | Revisor | Resultado | Observações |
|---|---|---|---|
| 2026-10-18 | agente | 🔧 | **A** (médio) o `THIRD_PARTY_LICENSES_ASSETS` estava **congelado**: dizia 287 pacotes npm enquanto o lock tem 245, sem a nota da exceção MPL e com Lucide 70 vs 71 arquivos — e `assets-licenses-check` validava a allowlist mas **nunca** a frescura do relatório (artefato legal da ADR-002) → regenerado + gate que compara o arquivo com o relatório recém-gerado (**provado vermelho** alterando o arquivo) — `fact_002gt3r5`; **B** (médio) a **Verificação da ADR-028** atribuía ao `tools/name-check` uma checagem de editores concorrentes que ele **não** faz (aquele gate cuida do **token de módulo**, ADR-004) → **emenda 6** no ADR + prova **executável** `RichTextExclusivityTest` (barra `filament`/`ckeditor`/`tinymce`/`quill` em `src`/`resources`/`config`/`tools` e exige `@tiptap/` só no serviço RichText), **provado vermelho** injetando `// ckeditor` no JS do portal — `fact_010yy1g9`; **C** (baixo) o índice do `AGENTS.md` dizia “ADR-001..041” mas não tinha o bullet da **041** → adicionado; **D** (obs) **15 ADRs** seguem “Proposto” com implementação fechada (009/010/011/012/028…) — aceite é decisão do humano — `risk_01irkxc8`; **E** (obs) todo o npm vive em `devDependencies` (o Vite empacota) e as cópias vendorizadas (fontes/ícones) vêm do npm sem gate de versão. Verificados e OK: **zero copyleft forte** (`assets-licenses-check` OK; `MPL-2.0` só nos 12 `lightningcss*`, build-only — a exceção estreita e nomeada da ADR-002; binários AGPL/GPL bloqueados por lista); allowlist permissiva cobrindo as **transitivas** (MIT 201, Apache-2.0 12, ISC 8, BSD 6+2, 0BSD, CC0, OFL, Python-2.0); zero CDN; **bundle só no CMS** (`editor.css` importado apenas pelo bundle do painel, o JS do portal não importa o editor e `@tiptap/` não sai do serviço); AST **sem HTML/CSS** (`jsonb`, nenhum nó de HTML livre, saída escapada). |

> Resultado: `✅ revisado` · `🔧 com correções` · `⏭️ delegado` (com justificativa).
