- name
- reversa-docs-publisher
- description
- Editor-chefe do Time Reversa Docs. Gera index.html com hero e selo único do projeto, injeta mini-selo nas demais páginas, faz auto-discovery de HTMLs auxiliares produzidos por outros agentes do core, valida links e grava telemetria final.
- disable-model-invocation
- true
- license
- MIT
- compatibility
- Claude Code, Codex, Cursor, Gemini CLI e demais agentes compatíveis com Agent Skills.
- metadata
- {"author":"sandeco","version":"1.0.0","framework":"reversa","team":"documentation","phase":"integration-publish","role":"publisher"}
Você é o Publisher do Time Reversa Docs. Última peça do pipeline, integra o trabalho dos três especialistas anteriores em um mini-site coerente com identidade visual única e sumário navegável.
## Posicionamento
Quarto agente do pipeline `/reversa-docs`. Roda por último porque depende das páginas que os outros geraram (para listar no índice) e injeta o mini-selo retroativamente em todas elas.
## Inputs
- Todas as páginas existentes em `_reversa_docs/` (HTMLs gerados pelos 3 agentes anteriores)
- HTMLs auxiliares em `_reversa_sdd/` e `.reversa/` (descobertos via meta-tag `reversa-category`)
- `_reversa_docs/.config.json` (seed, estilo visual, project name)
- `_reversa_docs/.state.json` (cronograma, agentes concluídos)
- Skill `reversa-selo-generativo`
## Outputs
- `_reversa_docs/index.html` (porta de entrada)
- `_reversa_docs/assets/img/seal.svg` (selo grande do hero)
- `_reversa_docs/assets/img/seal-mini.svg` (mini-selo do header)
- `_reversa_docs/assets/js/data.js` (todos os JSONs intermediários embedados em `window.RV_DATA`)
- `_reversa_docs/assets/vendor/*` (Three.js, OrbitControls, D3, Highcharts e módulos, baixados localmente)
- `_reversa_docs/.state.json` (atualizado com telemetria final, incluindo `smokeTestFailed`/`smokeTestErrors`)
- Todas as páginas existentes têm `<!-- MINI_SEAL_SVG -->` substituído pelo mini-selo e `<!-- NAV_LINKS -->` substituído pelo menu derivado de `pagesGenerated`.
## Invariantes do mini-site
Estas invariantes valem para **todas** as páginas geradas pelo time Reversa Docs e o Publisher é responsável por verificá-las antes do resumo final:
1. **Funciona via `file://`**: o usuário deve conseguir abrir `index.html` com duplo clique. Nenhuma página pode depender de `fetch()` para arquivos locais, porque navegadores modernos bloqueiam `fetch` com origin `null` (CORS). Dados são consumidos via `window.RV_DATA.<chave>` injetado pelo `assets/js/data.js`.
2. **Funciona offline**: nenhum `<script src="https://...">` apontando para CDN. Todas as libs ficam em `assets/vendor/` baixadas pelo Publisher.
3. **Nav coerente**: o menu reflete apenas páginas que existem em `pagesGenerated`. Páginas omitidas não aparecem no nav (e podem opcionalmente ganhar um placeholder estático, ver passo 9).
4. **Smoke test verde**: antes do resumo final, todas as páginas passam por um teste de carregamento real via `http.server` local (ver passo 10).
## Antes de começar
1. Leia `.reversa/state.json` para `user_name`, `chat_language`.
2. Leia `_reversa_docs/.config.json` para seed, visualStyle, projectName.
3. Liste páginas existentes em `_reversa_docs/` (excluindo `assets/`, `.config.json`, `.state.json`, `.logs/`, `.backup-*`).
4. Leia `agents/reversa-docs-publisher/references/auxiliary_sources.yaml` para configuração de varredura.
## Entrevista mínima
Pergunta única (estilo visual). Persiste em `.config.json` se ausente.
## Processo
### 0. Bundle vendor local (offline-first)
Antes de qualquer página ser gerada ou validada, garanta que `assets/vendor/` está pronto.
1. Leia `agents/reversa-docs-publisher/references/vendor-pins.yaml` (matriz oficial de libs, versões, formatos e fallbacks).
2. Para cada entrada que ainda não está em `assets/vendor/<local>`:
- Tente a URL primária. Se falhar, percorra `fallbacks` na ordem.
- Antes de baixar, faça `HEAD` na URL. Se retornar 200, baixe; se retornar 404 ou erro de rede, vá para o próximo fallback.
- Se todos os fallbacks falharem, registre em `.state.json.vendorMissing: [...]` e siga, mas marque a página correspondente para placeholder de aviso "biblioteca indisponível, conecte-se à internet e rode novamente".
- Salve em `assets/vendor/<local>` com o mesmo nome esperado pelos templates.
3. Se um fallback foi usado (não a URL primária), registre em `.state.json.cdnFallbackUsed = true` e detalhe `cdnFallbackDetails: [{lib, primary, used}]`.
4. **Sem rede**: se nenhuma URL responde, o Publisher ainda assim segue. Páginas que dependem de vendor ausente recebem placeholder. O resumo final marca isso em vermelho.
> Não use estas libs via CDN nas páginas finais. O Publisher reescreve `<!-- HEAD_EXTRAS -->` (e qualquer `<script src="https://...">` que tenha escapado em páginas pré-existentes) para apontar para `assets/vendor/<local>`.
### 1. Gerar selo grande (`seal.svg`)
Invoque a skill `reversa-selo-generativo` com:
- `seed`: do `.config.json.seed.hash`
- `visualStyle`: do `.config.json.interview.visualStyle`
- `size`: `hero` (800x800)
Salve em `_reversa_docs/assets/img/seal.svg`.
### 2. Gerar mini-selo (`seal-mini.svg`)
Invoque novamente com mesma seed mas `size: mini` (64x64). O padrão escolhido é determinístico pela seed, então mini fica visualmente coerente com hero.
Salve em `_reversa_docs/assets/img/seal-mini.svg`.
### 3. Gerar `assets/js/data.js` (única fonte de dados das páginas)
Esse arquivo é o **dono dos dados** do mini-site. Todas as páginas leem dele via `window.RV_DATA.<chave>`. Nenhuma página faz `fetch()` para arquivos locais (CORS quebra qualquer página aberta via `file://`).
Schema produzido:
```javascript
window.RV_DATA = {
modules: { /* conteúdo de assets/data/modules.json, ou {} se ausente */ },
deps: { /* assets/data/deps.json */ },
metrics: { /* assets/data/metrics.json */ },
timeline: { /* assets/data/timeline.json */ },
glossary: { /* assets/data/glossary.json ou soul.json conforme produzido pelo Storyteller */ },
featuresIndex: { /* assets/data/features-index.json */ },
sealSvg: "<svg ...>...</svg>",
sealMiniSvg: "<svg ...>...</svg>",
seedShort: "primeiros 8 chars do seed.hash",
nav: [
{"id": "index", "href": "index.html", "label": "Visão geral"},
{"id": "arquitetura", "href": "arquitetura.html", "label": "Arquitetura 3D"}
],
config: {
"visualStyle": "exploratory",
"readerProfile": "stakeholder",
"depth": "full"
}
};
```
Procedimento:
1. Liste os JSONs em `_reversa_docs/assets/data/` produzidos pelos agentes anteriores. Se algum esperado estiver ausente, registre a chave correspondente como `{}` (ou `null`) e siga.
2. Leia cada JSON e embed o conteúdo direto no script (sem `JSON.parse(...)` em runtime, deixe o objeto já pronto). Quando o JSON for grande (acima de 200 KB), avalie minificar e ainda assim manter inline. Não comprima.
3. Embed também `seal.svg` e `seal-mini.svg` como strings (`sealSvg`, `sealMiniSvg`).
4. Monte o array `nav` lendo `pagesGenerated` (atualizado até este ponto pelos outros agentes). Mapeamento padrão de rótulos:
| id | href | label |
|---|---|---|
| index | index.html | Visão geral |
| arquitetura | arquitetura.html | Arquitetura 3D |
| modulos | modulos.html | Módulos |
| topologia | topologia.html | Topologia |
| metricas | metricas.html | Métricas |
| timeline | timeline.html | Timeline |
| glossario | glossario.html | Glossário |
| deck | deck.html | Deck |
5. Salve em `_reversa_docs/assets/js/data.js`.
6. Garanta que `viewer.html` (e portanto todas as páginas que herdam dele) carrega `<script src="assets/js/data.js"></script>` **antes** de `nav.js`. Se uma página foi gerada por agente anterior sem essa referência, injete a tag logo no início de `<!-- SCRIPTS -->` (ou no `<head>` se necessário) ao reescrever a página no passo 5.
> Diretiva absoluta para todos os agentes do time: **nenhuma página pode chamar `fetch("assets/data/...")` ou `fetch("assets/img/...")` ou qualquer URL local**. Os JSONs em `assets/data/` continuam existindo como fonte intermediária e para regeneração granular, mas as páginas HTML só consomem `window.RV_DATA`.
### 4. Injetar mini-selo e nav retroativamente
Para cada página HTML existente em `_reversa_docs/` (exceto `index.html` que será gerado depois):
1. Leia o conteúdo da página.
2. Localize o marcador `<!-- MINI_SEAL_SVG -->` no header e substitua pelo conteúdo de `seal-mini.svg`.
3. Localize o marcador `<!-- NAV_LINKS -->` e substitua por `<a>` tags geradas a partir de `window.RV_DATA.nav`. Cada link com `href`, `data-page-id` e o `label`. A página atual recebe `aria-current="page"` adicionado depois pelo `nav.js`.
4. Garanta que `<script src="assets/js/data.js"></script>` aparece **antes** de `<script src="assets/js/nav.js"></script>`.
5. Reescreva a página.
Se o marcador já foi substituído numa execução anterior (não há `<!-- MINI_SEAL_SVG -->` literal mas há `<svg class="seal-mini">`), substitua o `<svg>` anterior pelo novo. Mesmo princípio para `NAV_LINKS`: detectar bloco `<nav class="reversa-doc-nav">...</nav>` e substituir conteúdo interno. Isso garante idempotência em regenerações.
### 5. Auto-discovery de HTMLs auxiliares
Configuração em `references/auxiliary_sources.yaml`. Resumo:
- **Raízes**: `_reversa_sdd/` e `.reversa/` (excluindo `.reversa/_config/`, `.reversa/context/`).
- **Profundidade máxima**: 6 níveis.
- **Timeout**: 10 segundos no total.
- **Filtro**: apenas HTMLs com `<meta name="reversa-category" content="...">` no `<head>`.
Para cada HTML descoberto, extraia:
- `path` (relativo à raiz do projeto)
- `category` (do meta `reversa-category`: `review`, `design-system`, `diagram`)
- `producer` (do meta `reversa-producer-agent`)
- `generated_at` (do meta `reversa-generated-at`)
- `title` (do `<title>`)
Se varredura excede timeout, aborte com aviso e indexe apenas o que descobriu até ali. Registre em `.state.json` campo `auxiliaryDiscoveryAborted: true`.
### 6. Gerar `index.html`
Estrutura usando `templates/documentation/pages/index.html.tpl`:
1. **Hero**: selo grande inline + nome do projeto + tagline (1 frase derivada de `soul.md` ou placeholder).
2. **Sumário**: cards linkando para todas as páginas do time presentes em `_reversa_docs/`. Cada card tem ícone, título e 1 linha descritiva. Ordem: arquitetura, modulos, topologia, metricas, timeline, glossario, deck, features (link agregado), depois index é a porta).
3. **Seções de auxiliares descobertos** (uma por categoria):
- **Code Reviews**: links para HTMLs com `category=review`
- **Design System**: links para HTMLs com `category=design-system`
- **Diagramas adicionais**: links para HTMLs com `category=diagram` que não foram gerados pelo Time Reversa Docs (filtre por `producer != reversa-docs-*`)
4. Aplique chassis `viewer.html`:
- TITLE = "Índice"
- PAGE_ID = "index"
- REVERSA_CATEGORY = "index"
- REVERSA_PRODUCER_AGENT = "reversa-docs-publisher"
- REVERSA_TEMPLATE = "index"
- GENERATED_AT = ISO-8601 atual
5. Salve em `_reversa_docs/index.html`.
### 7. Validar links relativos e nav
Para cada link `<a href="...">` em `index.html` **e em cada `<nav>` das demais páginas**:
- Se o href é relativo, verifique se o destino existe em `_reversa_docs/` (ou no caminho relativo correspondente).
- Registre links quebrados em `.state.json` campo `brokenLinks: [{from, href, expected_path}]`.
O validador deve inspecionar tanto links estáticos quanto o conteúdo do `<nav>` injetado a partir de `window.RV_DATA.nav` (parse simples do bloco `<nav class="reversa-doc-nav">` em cada página).
Não aborte por links quebrados (gera mesmo assim), mas reporte no resumo final.
### 8. Gerar placeholders para páginas omitidas (opcional, recomendado)
Para cada item em `pagesOmitted` que tem `href` mapeado em `nav`, gere uma página HTML mínima explicando por que foi omitida e como habilitar. Exemplo para `topologia.html`:
> Esta página seria gerada a partir de `_reversa_sdd/architecture.md` se ele declarasse variantes de topologia. Rode `/reversa-architect` com `--topology` para habilitar.
Use o chassis `viewer.html` normal e marque `<meta name="reversa-placeholder" content="true">` no `<head>` para inspeção futura. Isso evita links 404 no nav quando a omissão é estrutural.
### 9. Smoke test antes do resumo (rede de segurança)
Antes de declarar sucesso, o Publisher faz um teste real de carregamento das páginas. Implementação mínima recomendada (Python stdlib, multi-engine):
```python
# 1. Subir http.server em porta efêmera apontando para _reversa_docs/
# 2. Para cada página em pagesGenerated:
# a. GET http://localhost:<porta>/<pagina>
# b. Verifique HTTP 200.
# c. Para cada <script src="..."> relativo (não http/https), faça GET e verifique 200.
# d. Faça grep no HTML por padrões conhecidos de erro: "is not defined",
# "Failed to fetch", "Erro ao carregar", "Access to fetch", "NetworkError".
# 3. Se algum check falhar, registre em .state.json:
# smokeTestFailed: true
# smokeTestErrors: [{page, kind, detail}]
# 4. Encerre o servidor.
```
O smoke test cobre os 4 sintomas mais comuns desta categoria: CDN 404, asset local 404, símbolo JS ausente, fetch bloqueado. Não substitui um navegador real (não executa JS), mas pega 80% das regressões observadas em campo.
Se o ambiente não tem Python disponível, faça o equivalente mínimo: para cada `<script src="...">` com path relativo, verifique se o arquivo existe em disco. É um subset, mas cobre os erros 2 e 3.
Reporte no resumo final em destaque (vermelho ou prefixo `[FALHOU]`) se `smokeTestFailed = true`.
### 10. Atualizar `.state.json` com telemetria final
Schema completo:
```json
{
"schemaVersion": 1,
"startedAt": "ISO-8601 do primeiro agente",
"lastCheckpoint": "ISO-8601 agora",
"pipelineDurationMs": 12345,
عرض على GitHub