Pular para conteúdo

Changelog

Todas as mudanças relevantes deste projeto são documentadas aqui.

O formato segue o Keep a Changelog e o projeto adere ao SemVer — ver versionamento.

Unreleased

0.30.0 - 2026-08-04

Adicionado

  • Decisão 0019 — bibliotecas compartilhadas da casa. Infra idêntica cross-app (28 classes duplicadas na auditoria de 2026-08-03) passa a viver num único repo xadm-commons, cada lib = módulo Gradle com SemVer próprio, publicada como artefato Maven no Forgejo Packages; o app consome por versão (implementation("br.com.xadm:xadm-<lib>:X.Y.Z") + registro Forgejo por <VAR>/env). Base de pacote/group br.com.xadm (int-sascar migra de biz.xadm). Rejeitados repo-por-lib e git submodule (versão=SHA). Fim do copy-paste de infra; reduz o risco de drift do IdP Firebase compartilhado.
  • Decisão 0020 — contrato app↔app. Estende a 0012 (rota/método) fechando o corpo: quem recebe dita o contrato — o receptor publica OpenAPI (micronaut-openapi), o consumidor gera @Client+DTOs (openapi-generator) no build; versionamento com compat (janela de deprecação); envelope M2M (Bearer <APP>_API_TOKEN por callee, RFC-7807+code, 1 token/instância); status por caso (200-sempre onde PowerSync/fila exige, status real no par novo sem fila); request-id/MDC propagado entre hops; contract test consumidor×spec. Riscos §1.2 (capacidade do openapi-generator, janela de deprecação) declarados para a Fase 3.

Alterado

  • Engenharia: padrões de plataforma da leva 0019/0020. java-micronaut.md — HTTP app↔app dentro de Micronaut é @Client+@Retryable (OkHttp só em plain-Java), resolvendo a contradição com o transversal; camadas de lib em br.com.xadm.comum.* (pt-BR); nova seção registry de handler por tabela (XadmTableHandler<E>) como a forma anti-god-node de modelar o espelho X-Adm (refactor da Fase 4); o "gap declarado" de request-id/MDC vira norma (filtro no xadm-comum-web). integracao.md — nova tabela Arestas concretas (call-graph) (caller→callee : transporte : endpoint : auth). stack.md e powersync.md alinhados ao 0020 (OkHttp×@Client; o callback sempre-200 é o caso que exige 200 no status-por-caso). Constituição 0.27.5 (PATCH — sem artefato rastreado alterado; ADRs e páginas de engenharia são conteúdo de site, não templates do manifesto).
  • /xadm-release: a lista de venenos da skill passa a nomear redirect (2>&1, > arquivo) ao lado do pipe — comando com redirect é composto e não casa allow-list por ferramenta. O gap era só a skill rastreada: a 0.27.3 documentou o sonde-bare em agentes.md/ferramentas.md (páginas de site, que não vão pro repo de app), mas o agente no repo de app só enxerga a SKILL, onde o veneno "pipe" não mencionava o 2>&1. java -version tenta o reflexo de anexar 2>&1 (escreve versão no stderr) — o bare já casa java * e o harness captura o stderr. Espelhado na cópia local .claude/skills/xadm-release/SKILL.md. Constituição 0.27.4 (PATCH — templates/xadm-release-skill.md re-carimbado).

0.29.7 - 2026-07-31

Adicionado

  • /xadm-release: pré-flight passa a detectar teste OS-desabilitado e avisar sobre CI-verde. @DisabledOnOs(OS.WINDOWS)/@EnabledOnOs(OS.LINUX) é pulado no check local (dev = Windows), o gate fica verde cego e a divergência só aparece na CI Linux, pós-tag (caso real: v0.0.5 tagueada, CI vermelha depois). Agora o pré-flight Java procura essas anotações e, se acha, declara no relatório que N testes não rodaram (degradado, não silêncio) + recomenda rodar ./gradlew check no container ci-java:<v> (paridade Linux). O gate CI-verde é aviso, não bloqueio (o Coolify auto-deploya no push, item 62 — gatear o deploy é futuro): o relatório lembra de confirmar a run verde. Allowlist ganhou docker run *. Doutrina nova em ci-testes.md (§«Teste OS-desabilitado é gate cego no pré-flight») + ponteiro em java.md §Testes. Constituição 0.27.2 (PATCH — templates/xadm-release-skill.md re-carimbado).

Alterado

  • /xadm-release: allowlist do .claude/settings.json passa a ser por ferramenta (git *, node *, npm *, python */python3 */py *, mkdocs *, docker *, rtk *), espelhado nos namespaces Bash(...) e PowerShell(...), no lugar do allow-list por prefixo exato de argumento. O prefixo exato era quebradiço — cada variação de forma (interpretador python/py, npm install vs npm i, flag antes do subcomando, npm de dependência do lint-mermaid ausente) voltava a pedir prompt e travava o release no meio. Wildcard por ferramenta mantém o escopo (só as ferramentas do release) e elimina a fragilidade; o curl segue escopado de propósito. A garantia "só commita no release" continua sendo a REGRA Nº 2 (conduta), não o prompt. Venenos de comando composto (pipe, $(...), multi-linha) seguem valendo: ferramentas.md §Higiene e agentes.md §Loop de verificação ganham o mesmo padrão (sonde toolchain com comando bare, um por chamadajava -version, não java -version 2>&1 | head). Constituição 0.27.3 (PATCH — templates/xadm-release-skill.md re-carimbado).

0.29.6 - 2026-07-31

Adicionado

  • /xadm-release: gate de container para stack Docker Compose (serviço self-hosted, ex. PowerSync) no pré-flight. docker build prova que a imagem compila, não que a stack sobe — bootstrap (load de sync rules, migração) e healthcheck só rodam no up, e o primeiro a subir a stack de verdade é o Coolify em produção. Gate: docker compose -p <slug>-preflight up -d --wait (volume novo, healthchecks que a constituição §5 já obriga) + down -v; substitui o docker build se a imagem é pull (sem Dockerfile), soma se o repo builda. Opcional e degradável (sem Docker / falta .env / porta em uso = ambiente, não bug — declara no relatório). Allowlist ganhou docker compose * nos dois namespaces. Ponteiro em powersync.md §Deploy. Constituição 0.27.1 (PATCH — templates/xadm-release-skill.md re-carimbado).
  • Kit de UI: dois slots opcionais no navbar (layout.html) — ${appModo} (pill de ambiente à direita, renderiza quando presente) e ${appVersao} (versão discreta) — nos dois fragments (navbar e navbarComMenu), com estilo no custom-theme.css. Mata o hand-roll que já produzira drift (um app forkou o layout.html, outro pôs no conteúdo/navMenu). Receita em java-micronaut.md §UI com o ViewModelProcessor de referência que popula os dois em toda view: appModo só quando o ambiente ≠ produção (o layout não compara string), appVersao da config; detecção de prod e versão ficam app-specific. Constituição 0.27.0 (MINOR — funcionalidade nova, compatível; layout.html e custom-theme.css re-carimbados).
  • Armadilhas de render Thymeleaf em java-micronaut.md §Armadilhas: Thymeleaf standalone não tem os objetos implícitos de web (param/session/request, são do Thymeleaf-Spring) — controller lê do request e passa ao modelo; link com variável de path é @{/x/{id}(id=${..})}, não concatenação de String. Cura da família: bullet em §Testes prescrevendo o teste @Client que faz GET e renderiza de verdade (o ./gradlew check não renderiza template) + ponteiro em ci-testes.md §E2E (view server-render é fronteira de contrato).

Alterado

  • Publicidade de view sob micronaut-security: @Secured(SecurityRule.IS_ANONYMOUS) na rota vira o idioma primário (rota-exata por construção, sem allowlist paralela pra driftar); isPublicView() na SecurityRule custom fica para allowlist programática/dinâmica; segue proibido intercept-url-map greedy. Rota de view sem decisão explícita = 401. Atualizado em java-micronaut.md §UI, seguranca.md §Authn/authz e no checklist do revisor.

0.29.5 - 2026-07-30

Adicionado

  • Armadilha Gradle 9.5 + shadow + application: jar base e shadowJar com o mesmo app.jar quebram startScripts/build. Com o plugin application, startScripts/distZip consomem o output do jar; dividir o nome app.jar entre jar base e shadowJar faz o Gradle 9.5 acusar "uses this output of task ':shadowJar' without declaring … dependency". ./gradlew check é imune e o Coolify usa o shadowJar direto (produção não quebra) — morde só o dev que roda ./gradlew build. Cura: app.jar só no shadowJar (dê nome/archiveClassifier distinto ao jar base), ou startScripts { dependsOn(shadowJar) }. Bullet em java-micronaut.md §Armadilhas + nota cruzada no §Deploy; ponto cego declarado (sem gate — nada no pipeline roda build). Página dev não rastreada → sem bump.

Corrigido

  • Guarda de placeholder aninhado (templates/ci.yml) reprovava comentário — falso-positivo. A regex \$\{[^}]*\$\{ rodava em toda linha do application.yaml/.properties, inclusive comentário: um app que documenta a armadilha (# não use ${A:${B}}, full-line ou inline) fazia o CI falhar com ::error:: — o gate contra a armadilha proibia falar dela. Agora o step tira o comentário antes da regex (# no início ou pós-espaço) — o Micronaut não resolve comentário, então ignorá-lo é semanticamente correto; # literal em value (url http://a#b, properties k=a#b) fica intacto, e placeholder aninhado real (mesmo com comentário na cauda) segue reprovando. Constituição PATCH 0.26.6→0.26.7 (re-carimbo de templates/ci.yml).

0.29.4 - 2026-07-30

Adicionado

  • Norma "servidor local de verificação pega porta efêmera" (loop de verificação): subir servidor para conferir — app em modo debug, E2E local, preview — não fixa porta (8080/8000); pede porta efêmera e lê a URL que o processo imprime. Porta chutada colide com processo vivo ou zumbi e o sintoma engana (bind falha, ou responde outro servidor com build velho — episódio do mkdocs serve na 8000). Norma em agentes.md (§Loop de verificação) + ponteiro em ci-testes.md §E2E; mecânica por stack: Micronaut (MICRONAUT_SERVER_PORT=-1, ler Server Running:; EmbeddedServer.getURI() no E2E) em java-micronaut.md, Flutter web (flutter run já é random + imprime a URL; antipadrão é fixar --web-port) em flutter.md. Páginas dev não rastreadas → sem bump.

Alterado

  • Release da /xadm-release roda sem prompt de ponta a ponta — tag de 1 linha + allowlist Python por SO: a tag anotada era multilinha (string com \n não casa regra de prefixo) e pedia autorização em todo release — agora é resumo de uma linha (git tag -a v.. -m "v.. — resumo", o detalhe fica no CHANGELOG), casa git tag *, zero prompt. E o allowlist passou a cobrir o interpretador Python por SO (python3 no Linux, python/py no Windows) nos dois namespaces (Bash(...)/PowerShell(...)) — sem isso os gates do pré-flight pediam prompt um a um na máquina do dev. Vale para todos os apps: re-derivam a /xadm-release via /xadm-docs e alargam o próprio allowlist. Constituição PATCH 0.26.5→0.26.6 (re-carimbo de templates/xadm-release-skill.md).

0.29.3 - 2026-07-30

Adicionado

  • Seed de teste de endpoint Micronaut: @BeforeEach/@Sql, nunca no corpo do @Test + HTTP (loop §6, feedback de app): @MicronautTest default (transactional=true) faz rollback do corpo do teste, e o servidor embutido atende em outra conexão → não vê o não-commitado; o default SEPARATE_TRANSACTIONS commita o @BeforeEach, por isso seed lá fica visível e seed no corpo some (teste verde medindo vazio). Regra + mecânica em java-micronaut §Testes e fixtures, ponteiro em ci-testes §E2E. transactional=false não é a cura reflexa (quebra JDBC cru do @BeforeEach). Ponto cego declarado: nenhum gate estático pega. Páginas dev não rastreadas → sem bump.

0.29.2 - 2026-07-30

Corrigido

  • Placeholder aninhado no application.yaml do Micronaut NÃO funciona — receita da 0.29.1 corrigida (loop §6, bug de produção): o item 101 documentou o fallback de migração de env inter-app como ${NOVO:${ANTIGO:}} "o mesmo do SENTRY_DSN" — mas o SENTRY_DSN mora no logback.xml (motor que aninha, operador :-) e o Micronaut é OUTRO: o DefaultPropertyPlaceholderResolver casa o primeiro }, não o balanceado, então ${A:${B}} resolve pra lixo (token/URL inválido) sem erro de build → quebrou apps em produção. Correção: a receita de migração de env agora prescreve rename atômico ou resolve-in-code (duas props single-level), nunca cascata no yaml; armadilha nomeada em java-micronaut §Armadilhas (com a distinção logback×Micronaut); guarda nova no templates/ci.yml (grep de ${…${ só em app Micronaut — Spring aninha certo) pega reincidência no CI do próprio app. Constituição PATCH 0.26.4→0.26.5 (re-carimbo de templates/ci.yml).

0.29.1 - 2026-07-28

Adicionado

  • Convenção — ENV de auth/URL inter-app nomeada pelo DESTINO (loop §6): um Bearer/base-URL entre apps mora em <APP>_URL + <APP>_API_TOKEN ("como chamar o <APP>"); cada app valida o próprio <SELF>_API_TOKEN, cada chamador seta <DESTINO>_*. Token tem nome global com mesmo valor no callee (valida) e nos callers (mandam) → mapa de segredo coerente e sem colisão num app que é chamador e chamado (o API_BEARER_TOKEN homônimo com valor diferente por servidor foi o bug N-hop da integração Thoms). Um token por callee (trade-off declarado: revogar 1 caller rotaciona B pra todos). Migração de env sem quebrar produção por rename atômico ou resolve-in-code.

Regra no piso (seguranca.md §Segredos), receita de config em java-micronaut §Específico, ponteiro em integracao.md. Escopo: só HTTP inter-app (+ terceiros PARCEIRO_*); DB/ Firebase/observabilidade seguem como estão. Páginas dev — sem bump. - Java/Micronaut — 3 refinamentos vindos de feedback de app (loop §6): (a) convenção de rota /api/<origem>/<recurso> para callback/poke de um app a outro (<origem> = app chamador; integrador é o caso comum → /api/integrador/produto): /api/** é Bearer (ROLE_API), então o prefixo dá auth uniforme e contrato de rota previsível (§Específico + ponteiro em integracao.md §Transporte); (b) view pública se libera na SecurityRule da própria view (isPublicView(), rota exata), nunca por intercept-url-map greedy — o ConfigurationInterceptUrlMapRule roda em ordem -100 e ganha da SecurityRule custom, então um pattern /*//** com ALLOWED vaza rota irmã (ex. /admin) sem erro nem sinal (refina o piso em seguranca.md §Authn/authz + checklist do revisor; receita em java-micronaut §UI); (c) read-model de tabela de terceiro marca @Nullable o campo que a fonte pode deixar null — sem isso o Micronaut Data estoura "non-null constructor argument" e derruba o job inteiro (1 registro anômalo mata o sweep); trate ausência como anomalia (Sentry/WARN), não falha fatal (§Banco). Páginas dev, não rastreadas no manifesto → sem bump. - Constituição §6 — ponteiro para a higiene do .claude/settings.json (0.26.4) — um app perguntou se a constituição recomenda allow-list de permissões e concluiu "não" por olhar só a constituição-arquivo; a regra existe, mas vive em engenharia/ferramentas.md + app-novo.md (versionar o settings.json com padrões LARGOS dos comandos comuns — Bash(git *), Bash(mkdocs *), Bash(python3 scripts/*)… —, pessoal em settings.local.json gitignored; grant hiper-específico solta a tag da release via --amend). §6 ganhou um bullet-ponteiro (com a âncora da regra) para fechar a fresta de descoberta de quem só lê a constituição. Bump text-only.

0.29.0 - 2026-07-28

Adicionado

  • Gradle assado na imagem-fábrica ci-java (constituição 0.26.2) — feedback §6 (bi-transporte-xls v2.1.3): em cache frio o ./gradlew baixava a dist do Gradle de host externo e um UnknownHostException transiente pintava o gate de vermelho aleatório — a exceção acidental ao "zero download por run" (decisão 0003). Agora a ci-java pré-aquece a dist do wrapper (versão escalar gradle na matriz-baseline.json, casa-inteira) sob GRADLE_USER_HOME=/opt/gradle, no caminho-hash canônico; o ci.yml passa a cachear só deps. Egress do runner medido aberto (Maven Central, plugins, dist alcançam) → sem 2º furo. Adendo na decisão 0003: pareamento com gradle-wrapper.properties (versão E variante -bin), premissa distributionBase, ordem de bump anti-deadlock. Validado no runner (cold-cache não baixa; o smoke da fábrica assere a dist assada em /opt/gradle/wrapper/dists/); os 8 apps Java já pinam a URL canônica.
  • Manifesto EOL-agnóstico + guarda pré-commit da /xadm-release (constituição 0.26.3) — o gera-manifesto hasheava bytes crus (read_bytes), então gerá-lo no Windows (autocrlf/CRLF) divergia do Linux (LF) e deixou um drift subir silencioso no 0.26.1 (a entrada do xadm-release-skill.md não batia nenhum commit; o CI não-gating do item 62 só avisa). Agora hash_conteudo normaliza \r\n→\n antes de hashear (rastreia conteúdo, não bytes; binário preservado), com testa-gera-manifesto.py novo no CI. E o §8 da /xadm-release roda gera-manifesto --check como último passo pré-commit, fechando a race carimba→edita→commita.
  • Norma anti-deadlock no batch upsert (java-micronaut §Banco) — feedback §6 de app (Onpetro bi-comercial-xls v1.4.5, deadlock 40P01 real em produção): o diff-aware (ON CONFLICT DO UPDATE … WHERE … IS DISTINCT FROM) tira row lock na arbitragem do conflito, antes de avaliar o WHERE — linha "inalterada" trava igual, e duas transações concorrentes com dimensões sobrepostas em ordens diferentes deadlockam. Bullet novo: todo batch upsert ordena as linhas pela chave natural antes de executar (executeBatchsorted com nullsFirst; COPY + TEMP TABLEORDER BY no INSERT … SELECT), com a nuance multi-tabela e o teste proporcional (capturador de batch afirmando a ordem). Segundo feedback (bi-transporte-xls v2.1.3, mesmo risco corrigido preventivamente) completou o bullet: transação de mescla multi-fase (upsert + DELETE seletivo) serializa a fase de banco com pg_advisory_xact_lock(<chave fixa do app>) — o DELETE trava em ordem de scan, que ORDER BY não controla — e a declaração de que o deadlock em si não é testável deterministicamente: testa-se a pré-condição estrutural. Página não rastreada — sem obrigação nova.
  • Constituição 0.26.0→0.26.1 — allowlist Windows na /xadm-release e gitattributes-java (feedback §6 de app: release rodado em Windows nativo). (a) O bloco "Permissões — release sem prompt" do template xadm-release-skill.md só tinha regras Bash(...); no Windows o harness usa a ferramenta PowerShell, cujo namespace de regra é próprio (PowerShell(...)) — nenhuma regra Bash casa, e todos os gates promptavam na mão. O bloco Bash também não cobria os gates (só git + echo) — os gates promptavam no Linux idem. Agora os dois blocos são simétricos: git + gates de código/container/docs por stack ("mantenha só as da sua stack"; curl escopado em docs.xadm.biz). Cortados da proposta original os Get-Content/Select-String/etc. — o template já manda inspecionar arquivo pela ferramenta Read, nunca shell. Mais dois venenos Windows na lista: prefixo de env inline ($env:X='...'; cmd é composto — cura estrutural: "env" no settings.local.json) e sufixo ; echo "EXIT=$LASTEXITCODE" (idem; o harness já reporta exit code). Segundo feedback (bi-transporte-xls, ~15 prompts num release Windows) confirmou o diagnóstico e somou a regra python -m mkdocs build * (Windows raramente tem mkdocs no PATH), o par curl … http://localhost:8000/* pro preview local (o outro gerador recorrente de prompt) e a nota "URL antes do -o" no download de validadores; a receita git archive … | docker build - proposta lá foi rejeitada com o porquê no template (pipe é veneno de prompt, PowerShell 5.1 corrompe stream binário no pipe, e buildaria o HEAD em vez da árvore em curso) — a cura canônica do CRLF é o .gitattributes. (b) Template novo rastreado e opcional templates/gitattributes-java (gradlew text eol=lf): checkout Windows com autocrlf deixa o gradlew com CRLF, o docker build COPYa a árvore como está e o /bin/sh do Alpine morre com ./gradlew: not found — o --chmod=0755 do Dockerfile cura o bit de execução, não o fim de linha. Referenciado em constituição §3, templates.md (tabela + seção Container), app-novo.md §7, java-micronaut §Deploy, gate de container do release e mapeado pela /xadm-docs (gitattributes-java.gitattributes). Bump PATCH; 4 rastreados re-carimbados (xadm-release-skill.md, xadm-docs-skill.md, dockerfile-java, gitattributes-java).

0.28.0 - 2026-07-23

Adicionado

  • Constituição 0.25.1→0.26.0 — plataforma de integração ganha topologia e fluxos em SVG autoral, o livro ganha capa obrigatória, e a taxonomia um 5º papel: app compartilhado. Pedido interno: a diretoria precisa ver a plataforma em uma tela (X-Adm no cliente, nuvem, terceiros). A documentacao/integracao.md era só prosa — sem figura, o chefe tinha que ler taxonomia + tipos + fronteiras para montar a topologia na cabeça. Adicionado no topo da página: §Topologia — depois de rodadas contra o layout automático (Dagre inverte ranks por ciclo/aresta; block-beta dá grid mas sem rowspan nem título de composite), a figura final é SVG autoral (docs/assets/topologia-integracao.svg — base visual desenhada pelo Gustavo, paleta re-tokenizada para X-Adm royal #064490 + tipografia Inter, decisão 2026-07-22), embutida via --8<--, com Mermaid-base colapsado logo abaixo (??? infopymdownx.details habilitado no mkdocs.yml) como fonte semântica lintada: mudou a topologia, atualiza o base primeiro e espelha no SVG. Norma nova: bullet "Figura autoral (SVG) — a exceção de capa" na constituição §5 + receita completa em templates.md §"Figura autoral em SVG" (as armadilhas reais: linha em branco ou <svg> sem wrapper <div> fatiam o SVG em <p> — python-markdown não trata <svg> como bloco; <style> sem prefixo vaza pro site; <img> não herda a webfont, daí --8<--), com o ponto cego declarado: nenhum gate valida o SVG em si — quem é lintado é o Mermaid-base. CSS auxiliar em docs/stylesheets/xadm.css: .md-typeset .mermaid com overflow-x: auto (vale para os demais diagramas Mermaid do site). Rótulos da figura (por pedido interno): Hub = "Plataforma de Integração" + int.<cliente>.xadm.biz + ps.<cliente>.xadm.biz; banco = "PostgreSQL Cliente ¹" com nota de rodapé "Um banco de dados por cliente"; apps específicos = "Apps Específicas" (agrupa pied e excel); app compartilhado = "Apps Compartilhados". Papel novo — App compartilhado: 1 instância multi-tenant que nasce quando o parceiro é global (mesmo endpoint para N clientes, cada um com sua credencial); não escreve no barramento (mantém §Fronteiras "um dono por tabela" intacta), conversa com o hub, que grava. Combina tipos ③+④ quando o parceiro é bidirecional. Motivo concreto: sascar.xadm.biz — o hub envia MDF-es abertos (chave/placa) ao app compartilhado, que faz polling na Sascar do cliente com credenciais próprias; quando o motorista chega ao destino, devolve encerrado ao hub, que atualiza o status; o cliente Java lê via PowerSync e importa no ERP. Reator removido da taxonomia — reservado para uso futuro. O único caso concreto (thoms → e-commerce) foi confirmado como REST puro ao ler a UI do app rodando (POST /sync/erp em webstorm-ecom.thoms.xadm.biz, sem PowerSync no servidor). A definição "não recebe de fora, consome o banco via PowerSync, empurra para fora" contradizia o caso real; thoms virou app específico (ecommerce.<cliente>) que recebe do hub via REST e faz POST no parceiro (WebStorm). O papel Reator fica reservado para casos futuros de notificação (email, push, alertas Telegram) — quando aparecer, volta à taxonomia. Aplicado em: figura (zonas Servidor X-Adm Cliente com ERP X-Adm ↔ Integrador Cliente — as saídas partem do Integrador, label "push tempo real"/"write-back" — / Terceiros / Nuvem 2x2 / Usuários com mockups de navegador e celular; Sascar → Apps Compartilhados via pull · MDF-e, odômetro e Plataforma ↔ Compartilhados via REST · baixa MDF-e, odômetro; PowerSync PG → Usuários e PG → Integrador; write-back dos Usuários por fora; sem badges numerados — os 4 tipos são numerados no texto, não na figura); §Taxonomia (linha Reator removida, App consumidor menciona Web/Mobile); §Os 4 tipos (item 4 reescrito; admonition "Reator — reservado para uso futuro"); §Fronteiras (regra de tabela de status separada agora fala em app específico); §Transporte (PowerSync serve consumidor + cliente Java; hub↔apps específicos é REST); tabela de prefixos (<app>_ cita xls_*, thoms_envio); constituição §8 (Taxonomia sem reator; PowerSync bidirecional distingue consumidor de app específico REST; fronteira §7 sem reator; contrato sem "packaging de reator"); glossário (seção Reator removida); engenharia/powersync.md (2 lugares). Rejeitado replicar sascar.<cliente> (N deploys idênticos batendo na mesma API, isolamento sem benefício), rota no hub (reintroduz o erro (a) da §integracao.md), e app compartilhado escrevendo no barramento (dois donos à tabela-espelho — quebra §Fronteiras). Terminologia — rename da taxonomia: "vertical" → app específico; "adaptador compartilhado" → app compartilhado (feedback interno: a taxonomia da plataforma agora fala em apps por papel, não em jargões técnicos). Aplicado em integracao.md (§Taxonomia + §Os 4 tipos + §Fronteiras + §Transporte), constituição §8, glossário (2 seções + Owner-writes), decisão 0018 (título + corpo; slug preservado 0018-adaptador-compartilhado.md para não quebrar links; nota de terminologia dentro do arquivo) e nav do mkdocs. Também trocado "shape" por "tipo de fluxo" na página e no §8 — "shape" era jargão a mais para a equipe. "Shape" segue em outros contextos da constituição (formato de resposta HTTP, shape de fixture), onde não colide. Trocado "pola a API" por "faz polling na API" — anglicismo técnico consagrado, "pola" era gíria. Removido bi-commons da doc normativa (integracao.md, constituição §8, glossário, powersync.md): a biblioteca não foi implementada ainda, e a doc presumindo sua existência viola §1.6 (não inventar). Decisões 0007 e 0014 preservam a menção como registro histórico da intenção — o dia que a biblioteca existir, volta à norma. Adicionado: decisão 0018 + linha na tabela §Taxonomia + nota "combinação ③+④" em §Os 4 tipos; §8 da constituição inclui app compartilhado na taxonomia (anti-drift §8). Detalhe operacional (auth por cliente, schema do banco de trabalho, contrato exato com o hub) fica na arquitetura-alvo do integrador (§1.9: concreto no repo dono). §Fluxos novo na integracao.md: 3 SVGs autorais verticais (um por fluxo, cima→baixo: fluxo-saida.svg, fluxo-entrada.svg, fluxo-ciclo-mdfe.svg, mesma UI da topologia; escolhidos contra a variante combinada horizontal, que perdia legibilidade no downscale da coluna — a vertical cabe inteira, fonte no px desenhado) — saída X-Adm→Usuários (rotas tempo real e batch XLSX), entrada Externo→X-Adm (PIED, com devolução de status) e o ciclo completo do MDF-e (Sascar) — cada um com a faixa COMO ACOMPANHAR (exceções de software vão automaticamente ao GlitchTip com notificação à equipe; exceções de operação geram e-mail à equipe do cliente). Capa obrigatória no livro (cap. 0): a constituição §2 passa a exigir que a Documentação Completa abra com figura de topologia + fluxos principais com "como acompanhar" (Mermaid por padrão, SVG autoral permitido via §5); templates/projeto-index.md ganha a seção "0. Capa" com o marcador HUMANO — projeto novo nasce com capa, app existente adota por migração oportunista (§1.6). Rename editorial: "hub" → "Plataforma de Integração" em toda a doc normativa (integracao.md com desambiguação plataforma-conjunto × Plataforma-serviço, constituição §1.9 e §8, glossário, powersync.md, decisão 0018 — decisões 0007/0014/0016 ficam, são histórico) e "empurra" → "envia" (registro). Bump MINOR — a capa é obrigação nova sobre o livro (o resto é permissão + esclarecimento + rename); 0 rastreados mudaram (projeto-index.md é scaffold de uma vez, não rastreado — quem o cobra é a constituição §2, não o manifesto).

  • engenharia/java-micronaut.md §Banco — bullet novo: chave-de-mudança single-writer via @DateUpdated. Feedback de app (§6). A doc já tinha o par multi-writer (trigger Postgres, entidade não mapeia — evita null-wipe) mas nada para o caso simples: app dono único da tabela onde @DateUpdated do Micronaut Data resolve de graça (carimba a cada write, rejeita valor externo, serve ORDER BY updated_at a consumidor externo). Bullet novo entre §Espelho fiel e §multi-writer fecha a matriz "dono da escrita → onde vive o bump" (single → ORM mapeia; multi → trigger, entidade não mapeia). Sem bump — página não rastreada; mudança de conselho, não de contrato.

  • /xadm-release pré-flight — aviso soft do bloco 'Publicar Release' comentado. Feedback de app (§6). O templates/release.yml traz o bloco de asset e o permissions: contents: write comentados por default (OPT-IN "só app que distribui artefato"). App que copiava o template e distribuía artefato mas esquecia de descomentar → valida-release.py verde, tag pushada, aba Releases vazia, jar sem asset — descoberto só quando o operador ia baixar. Irmão silencioso do item 95 (descomentar sem trocar container: é barulhento — guarda + 403 — ; NÃO descomentar quando deveria era o cego). Adicionado bullet no pré-flight do templates/xadm-release-skill.md: se .forgejo/workflows/release.yml existir, lê pela ferramenta Read e procura DOIS marcadores literais (# - name: Publicar Release no Forgejo e # contents: write); se algum aparecer comentado, avisa no relatório final (não bloqueia — app só-deploya/doc-only ignora legitimamente). Sem release.yml → skip. Rejeitada a alternativa "cobrar campo distribui_artefato no app.json" (bandeira nova a manter, sem gate para cobrar); o próprio release.yml carrega os marcadores do template quando foi copiado → detecção sem inferência, sem falso positivo. xadm-release-skill.md re-carimbado; cópia do central (.claude/skills/xadm-release/SKILL.md) inalterada — o central não distribui artefato (site MkDocs, deploy por push).

0.27.2 - 2026-07-20

Alterado

  • Constituição 0.25.0→0.25.1 — o checa-rotas.py confere rota, não forma: a fronteira agora é princípio, não nota de rodapé. Feedback de app: publicar um arquivo-fato de contrato ao lado de um OpenAPI cujo schema mentia (required/enum/nullability ≠ runtime) passou os dois gates — quem pegou foi o teste de fio, não a toolchain. O ponto cego já estava declarado ("o check não sabe nada sobre corpo — só rota e método"), mas como nota mecânica. Avaliada e recusada a extensão a um check de schema-drift prosa×spec: o spec gerado é oráculo confiável de rota (path/verbo saem fielmente das annotations) mas frágil de forma (não vê validação imperativa, default, serialização custom), então um gate prosa×spec passaria verde com ambos mentindo juntos (o teste tautológico do item 88 por outro caminho) ou acusaria a prosa correta quando ela acerta o runtime e o spec erra — falso conforto. O oráculo independente de forma é o runtime = teste de fio, que já é piso §6 (E2E na fronteira de contrato). Reforço em três lugares: §Contrato REST (o princípio "rota é checável contra o spec, forma não é"), a docstring do checa-rotas.py, e o padrão do arquivo-fato em publicar-docs.md (o autor que escreve schema em prosa "a partir do código" atesta a forma por fio, não por gate). Sem mudança de comportamento — esclarecimento do escopo já existente; o checa-rotas.py (rastreado) foi re-carimbado.

Adicionado

  • Constituição 0.24.1→0.25.0 — o kit de UI ganha app.css: CSS de componentes do app, sempre linkado. O head(title) do layout.html passa a linkar /css/app.css depois do custom-theme.css, e a /xadm-docs scaffolda o arquivo de templates/app.css na criação do app. Dois CSS, dois donos (§1.9): o custom-theme.css é a identidade da casa — rastreado, verbatim, não se edita por app; o app.css é dos componentes do app (timeline, tiles, stepper, badges de domínio), não é rastreado e o central nunca o re-deriva. A 0015 fechou o slot de <head> com razão (dois <head> quebram toda view) mas deixou o app sem lugar para o CSS dele, e a saída prescrita — "escreva o <head> à mão nessa tela" — não escala para 16 telas. Não era hipótese: dois apps já contornavam a lacuna, de formas diferentes — o int-pied emitindo o <link> no <body> via fragment local, e o bi-comercial-xls forkando o layout.html. O fork é o dado que decide: o layout forkado ainda carregava um fragment morto que o central removera há duas versões — fork sai do radar do /xadm-docs e para de receber correção. Os dois apps escolheram o mesmo path (/css/app.css) independentemente: o kit passa a prescrever o que já era fato. Detalhe em 0017 e na receita Java/Micronaut §UI.

    Nenhum app quebra: as views seguem chamando head('Título') com um parâmetro, e não há segundo <head> — a 0015 continua valendo, slot de markup arbitrário no <head> segue não existindo. Migração: app que usa o kit e re-derivar o layout.html precisa ter public/css/app.css, nem que vazio (sem o arquivo, 404 em toda página). Os dois contornos atuais continuam funcionando — ninguém precisa correr.

Corrigido

  • Constituição 0.24.1→0.25.0 — templates/mkdocs.yml declarava exclude_docs: duas vezes: o privado/ sumia em silêncio. Bug introduzido na 0.24.0 (arquivo-fato): o segundo exclude_docs:, 48 linhas abaixo do primeiro, sobrescrevia o bloco de cima — e aquele bloco excluía privado/, o segmento reservado a confidencial de cliente (§5). Todo app que re-derivasse o template verbatim passaria a publicar docs/privado/ no site. YAML não avisa sobre chave duplicada, e o --strict fica verde por estar certo: para o MkDocs a chave apagada nunca existiu. Repro: python3 -c "import yaml; print(yaml.safe_load(open('mkdocs.yml'))['exclude_docs'])". Cura: os dois blocos fundidos num só, com o porquê no topo.

  • O checa-nav.py passa a reprovar chave YAML repetida no mkdocs.yml — a classe, não o sintoma: dois nav:, dois plugins:, dois theme: falham igual. Parser de indentação stdlib (o check roda no gate de código do app, onde não há PyYAML — e yaml.safe_load não serviria: ele é quem come a duplicata em silêncio; para vê-la é preciso olhar o texto). Verificado nos dois sentidos: reprova o templates/mkdocs.yml real de antes da correção (exclude_docs na linha 91, já declarada na 43) e passa nos 7 mkdocs.yml reais da casa, sem falso positivo. A guarda de privado/ do docs.yml continua sendo a rede de baixo, mas só pega o sintoma daquela vez, depois do build e só nos apps que a têm. Detalhe em CI, gates e testes.

  • Constituição 0.24.0→0.24.1 — docs.yml e release.yml: o container: e o bloco Java agora se amarram. O container: (topo) e o bloco de geração de API (~120 linhas abaixo, comentado) eram acoplados em silêncio: descomentar o bloco sem trocar o container: de ci-base para ci-java:<v> derruba o workflow no push com JAVA_HOME is not set. O defeito é invisível a todos os gates — o ci.yml já vem com ci-java e passa verde, e o pré-flight da /xadm-release builda na máquina do dev, onde há JDK; só o push descobre, e no release.yml a tag já está no ar. Pior: a mensagem nativa do gradlew manda setar JAVA_HOME, que é o antipadrão da casa (decisão 0003 — a toolchain vem da imagem, sem setup-java). Agora o comentário do bloco cobra a troca do container: e uma guarda (command -v java) transforma o erro numa instrução que aponta o container:. O release.yml levou a mesma guarda: ele já tinha o comentário e o mesmo defeito.

0.27.1 - 2026-07-17

Corrigido

  • Constituição 0.24.0→0.24.1 — o Dockerfile canônico manda o app rodar como USER app num WORKDIR que é de root. O WORKDIR /app cria a pasta como root (o --chown do COPY é do jar, não dela); depois do USER app (uid 1001) qualquer escrita sob /app — log em caminho relativo, cache, upload, diretório de trabalho — falha com AccessDeniedException em runtime, na produção: o build passa, o teste passa e o docker build do pré-flight também. Reproduzido com Docker de verdade (mkdir /app/logs e touch /app/xPermission denied). No bi-comercial-processador-xls isso derrubou todo o processamento (logback em logs/app.log, createDirectories(/app/logs) falhando antes de qualquer trabalho). Agora o templates/dockerfile-java traz, no ponto exato antes do USER app, a regra + a receita comentada (RUN mkdir -p /app/logs && chown app:app /app/logs), com o aviso de não usar chown app:app /app inteiro (o app sobrescreveria o próprio app.jar — metade do motivo de rodar não-root) e de conferir o arquétipo antes (servidor loga em stdout, quem loga em arquivo é CLI/worker — logs/ num servidor costuma ser logback.xml do arquétipo errado). O java-micronaut.md §Deploy ganha o bullet-dono; o coolify.md troca o exemplo /app/logs de Storages (arquétipo errado) e documenta a herança de dono: volume nomeado herda o dono do diretório da imagem — se o diretório não existir, nasce root e quebra igual —, bind mount não herda (o dono no host é que precisa ser 1001:1001).

0.27.0 - 2026-07-16

Adicionado

  • Constituição 0.23.3→0.24.0 — arquivo-fato ganha hospedeira obrigatória, e sai do build com exclude_docs:. A 0.23.0 mandou o dono publicar o fato, mas a receita dizia que ele "vive em docs/public/ como qualquer página" e leva not_in_nav: — duas metades que não fecham: sem uma página que o embuta, o fato só existe no raw/, invisível no site do dono. E not_in_nav: não esconde, só cala o aviso de órfã: o fragmento continua sendo buildado, ganha um H1 inventado do nome do arquivo ("Xadm ingest"), fica alcançável por URL e entra na busca — procurar "Envelope" devolve a hospedeira e a órfã, com o mesmo texto. Agora: a hospedeira (public/contratos/index.md, no nav:, com frontmatter) é obrigação do dono, e os fatos saem do build com exclude_docs: + ! reincluindo a hospedeira. O --8<-- e o rclone/cp do raw/ seguem funcionando — leem do disco, não do build. Vale nos dois lados: _importado/ também é exclude_docs:, senão o site do consumidor serve o contrato do dono como se fosse página dele — a cópia que o mecanismo existe para matar. not_in_nav: fica para o que deve sair no site sem estar no índice (o Javadoc em dev/api/). Decisão 0016.

    Migração — quem já publica fato troca not_in_nav: por exclude_docs:

    Um repo publica arquivo-fato hoje (o hub de integração) e já tinha escrito a hospedeira por conta própria. Trocar o not_in_nav: pelo exclude_docs: do templates/mkdocs.yml tira a órfã do ar. Sem a troca nada quebra: o site só segue servindo a página órfã e duplicando o texto na busca.

  • Página em docs/public/ leva frontmatter — inclusive a da API. Havia duas convenções: o templates/public-api.md sem frontmatter, a hospedeira do hub com. Governança por documento (§6) não abre exceção por a página ser pública, e para quem consome um contrato o cabeçalho é o que importa: atualizado: diz se o contrato está vivo, status: se dá para confiar, responsavel: a quem perguntar. O hook expõe o nome, nunca o e-mail.

  • Constituição 0.23.1→0.23.2 — checa-admonition.py: admonition cru vira gate. O mkdocs build --strict não pega marcador mal indentado: para ele não há erro, só um parágrafo que começa com !!! — renderiza literal e sai verde, e quem paga é o leitor. Mesma classe do Mermaid que não parseia (a razão do lint-mermaid.mjs), e foi achado no olho de um humano, que é o gate que a §6 diz não servir. O check roda depois do build e confere o HTML, não o Markdown: ali não há ambiguidade — !!! em <pre> é código exibido (esta plataforma mostra o runbook.md, que tem um !!! warning de exemplo), em <p> é bug. No build-site.yml, no docs.yml dos apps e no pré-flight da /xadm-release.

Corrigido

  • checa-nav.py — a negação ! de exclude_docs: era ignorada, e os globs vinham sem ordem. Dois bugs que só apareceram ao prescrever a hospedeira, e que a teriam transformado numa órfã silenciosa: o veredito parava no primeiro glob que casava (então /public/contratos/*.md dava a hospedeira como excluída e ela podia sumir do nav: sem ninguém acusar), e os globs eram acumulados num set — sem ordem, num formato em que a ordem decide (última que casa vence, como no .gitignore). Um terceiro: o regex que varre o mkdocs.yml capturava os próprios globs de exclusão como "menção de nav", dando passe livre a fato que nenhum exclude cobria. Três casos novos de regressão; mutação confirmada (o _excluido antigo deixa caso vermelho).

  • testa-checa-views.py — a fixture agora é o kit real, com guarda de mutação. O LAYOUT_OK era cópia à mão do layout e já tinha divergido dele uma vez (ficou com o layout quebrado da 0.21.0 e a suíte seguiu verde durante todo o bug). Agora lê templates/views/layout.html. A guarda existe porque ler o real só é melhor se a mutação for garantida: muta() exige que o alvo apareça exatamente uma vez — pega tanto o no-op (o kit mudou, o alvo sumiu) quanto o alvo ambíguo. Não é hipótese: ao trocar a fixture, os dois casos da regra G passaram a injetar o <head> defeituoso dentro do comentário de cabeçalho do kit (onde o parser não olha) e ficaram verdes testando nada — a guarda os pegou.

  • Constituição 0.23.2→0.23.3 — o kit de UI da 0.21.0 estava quebrado no ar: slot de head removido. O fragment headComExtras(title, extras) era um segundo elemento <head> no layout.html, e um documento HTML tem um só: o parser funde o segundo no primeiro, e o head('Título') passou a arrastar o ${extras} do irmão — Error resolving fragment: "${extras}", 500 em toda view, inclusive nas que não usavam o slot. A afirmação da 0.21.0 de que "as telas que já chamam head('Título') seguem intactas" era falsa. Reproduzido com Thymeleaf 3.1.5 antes de decidir: não é colisão de nome (renomear não cura) nem "head dentro de body" (dois <head> irmãos quebram igual) — basta serem dois. O slot foi removido em vez de consertado: 0 views o usavam, 126 chamavam head(). Tela que precise de markup próprio no <head> escreve o <head> à mão e traz o caso ao central. Decisão 0015.

    Migração — quem copiou o kit 0.21.0/0.22.x re-deriva com /xadm-docs

    O layout.html volta a ter só head(title). Nenhum app usava o slot, então não há chamada a corrigir: quem estava com o kit quebrado volta a renderizar; quem nunca adotou não faz nada.

  • checa-views.py — regra G: <html>/<head>/<body> duplicado no mesmo arquivo reprova. É a guarda contra a reincidência do bug acima. Vale mesmo com nomes distintos e mesmo fora do <body> — o que quebra é o parser fundir elemento, não o nome (a regra A já cobria nome). Só declaração real conta: o cabeçalho do kit documenta o uso com um <head th:replace=...> dentro de comentário, e os três apps Micronaut reais têm isso — a regra lê o parser, nunca regex. Verificada nos dois sentidos: reprova o layout.html real da 0.21.0 e passa nos 46 views reais dos três apps.

  • testa-checa-views.py — a fixture LAYOUT_OK era o layout quebrado. O "layout conformante mínimo" da suíte trazia o segundo <head>: o teste do checker atestava contra um defeito, que é a fixture inventada que a §6 nomeia — e o motivo de a suíte não ter pego nada. Corrigida, mais quatro casos da regra G (o bug real, os dois <head> irmãos, <body> duplicado e o negativo do <head> em comentário).

  • checa-rotas.py — a mensagem de erro dizia onde pôr o escape de forma ambígua. Dizia "<!-- checa-rotas: ignorar --> na linha"; um dev de app leu como "na linha de cima" e perdeu um ciclo de gate. Agora diz na MESMA linha da rota, e que o marcador não aparece na página (é comentário HTML). Só a string mudou — o escape sempre foi por linha, e segue.

  • Nota de migração da 0.23.1 renderizava crua na /changelog/ — o !!! note estava indentado com 2 espaços dentro do bullet e saiu como texto literal na página publicada. Python-Markdown usa tab_length = 4: parágrafo de continuação de item de lista aceita 2 espaços (lazy continuation), mas bloco novo — que é o que o admonition é — exige 4; com 2, ele cai fora da lista e vira parágrafo. O texto ao redor sai perfeito, então o erro não chama atenção no diff.

0.26.0 - 2026-07-16

Adicionado

  • Constituição 0.21.0→0.22.0 — o contrato REST passa a ser checado contra o OpenAPI gerado: checa-rotas.py (loop §6, feedback de app). A §6 mandava a doc mudar no mesmo PR que muda o contrato, e nada detectava quando isso não acontecia — a própria §6 admitia não ter "detector automático de doc seguiu código". Num app, uma rota de upload foi renomeada no controller; o OpenAPI, que o micronaut-openapi deriva dos @Controller ao compilar, acompanhou sozinho; a prosa não. Por 10 dias o mkdocs build --strict, o checa-nav e o ci.yml ficaram todos verdes enquanto o site publicado servia o contrato novo e a prosa com a rota morta, lado a lado. O checa-rotas.py (rastreado, stdlib, baixado fresco, tolerante) confere prosa → spec e roda no ci.yml (depois do ./gradlew check, que é quando o spec existe — o rename é evento de código) e no docs.yml (prosa editada sem tocar código, inclusive pela web do Forgejo). Só cobra rota cujo primeiro segmento existe no spec, para não reprovar API de parceiro que o app só consome nem rota de app vizinho; aceita prefixo de família em diagrama; pula documento status: obsoleto; e tem escape de linha <!-- checa-rotas: ignorar --> para a decisão de remoção, que não tem como nomear a rota removida sem escrevê-la. Aplicado aos dois apps que geram OpenAPI, achou o drift do feedback e um segundo bug inédito (doc cuja seção diz "Envie um PUT" e cujo exemplo diz POST, numa rota que só expõe PUT/DELETE). Decisão 0012; detalhe em CI, gates e testes.

Corrigido

  • Constituição 0.23.0→0.23.1 — o kit de UI mandava o CSS para um diretório que não o serve (loop §6, feedback de app). A /xadm-docs mapeava templates/views/**src/main/resources/views/**, mas templates/views/ tinha dois arquivos com destinos diferentes: o layout.html é view, o custom-theme.css não — quem serve views/ é o Thymeleaf, e o CSS precisa do static-resources (public/css/), como o próprio arquivo dizia no cabeçalho e o @{/css/custom-theme.css} do layout referenciava. Seguir o glob ao pé da letra sobe a tela sem estilo. Bug latente, nunca exercitado: os dois apps Micronaut reais têm o CSS no lugar certo porque nasceram antes do kit — o primeiro app novo a seguir a skill é que quebraria. A cura foi a origem, não o mapeamento: o custom-theme.css foi para templates/public/css/, e a árvore do kit passa a espelhar a do app — os dois globs viram verdade (views/**views/**, public/**public/**), sem exceção por arquivo a manter em sincronia. Listar arquivo-por-arquivo na skill (o que o feedback pedia) duplicaria a tabela que já é dona no java-micronaut.md — recriando o segundo dono que causou o bug. Guarda nova: o checa-views.py ganha a regra F (arquivo não-.html em views/ reprova, apontando public/), que mata a classe e não só este arquivo.

    Nota de migração — só o path de ORIGEM muda

    O destino no app não muda: quem já tem public/css/custom-theme.css está correto e nada precisa fazer. Mudou o caminho no manifesto (templates/views/custom-theme.csstemplates/public/css/custom-theme.css), então a /xadm-docs re-baixa do raw novo. App que tenha o CSS em views/ (nenhum conhecido): mova para public/css/ — a tela está sem estilo.

Alterado

  • Constituição 0.22.1→0.23.0 — fato de outro repo: o dono publica em raw/, o consumidor importa no build (loop §6, feedback de app). A 0.22.1 abriu transclusão para fato do mesmo repo e manteve "cross-repo é link, sempre". O caso que sobrou é o runbook de implantação de um vertical, que vive entre dois apps: o que ele implanta é seu, o contrato de ingestão que ele consome é do hub. O diagnóstico mudou a pergunta — o hub não publica o OpenAPI que ele já gera (step comentado), não tem docs/public/, e seu contrato vive espalhado em dez arquivos de prosa. Não havia o que linkar: a cópia era sintoma, o dono que não publica é a causa, e a regra parava no consumidor. Agora: o --8<-- não atravessa repo, mas o build atravessa — o dono publica o .md cru na raiz do seu prefixo (docs-sites/<slug>/raw/, aditivo, todo push, pelo mesmo critério que já põe o app.json lá: é contrato entre apps, não conteúdo versionado), e o consumidor faz curl -f para docs/_importado/ (efêmero: .gitignore + not_in_nav:) e embute. O fato chega fresco a cada build; curl -f falha o build se o dono despublicar. Publicar é obrigação do dono, e quem rege a evolução de um repo não vira dono dos fatos dele — o projeto-mãe escreve o PR no dono e importa aqui, senão um hub compartilhado ganha um dono por consumidor. Decisão 0014; receita em Publicar docs.

  • Constituição 0.22.0→0.22.1 — o runbook transclui do arquivo-dono; re-digitar é que é proibido (loop §6, feedback de app). A 0.20.2 fechou "o livro não entra no runbook" e mandou o runbook linkar; um dev aplicou a regra e reverteu, porque a versão conforme ficou pior para o uso real — mostrar a integração à equipe numa página. O ponto procede por um motivo mais forte que o custo ao leitor: a regra contradizia o princípio que deveria implementar (o §1.9 já dizia "linkam ou embutem (pymdownx.snippets), não copiam"). Agora: onde o operador precisa do fato na mesma página, o runbook transclui do arquivo-dono — não há cópia para envelhecer. Transclui-se do arquivo-fato, nunca "da seção do livro" (o livro é narrativa e ele próprio embute os fatos); cross-repo continua link, que é onde o exemplo-que-mente nasceu. O §2 passa também a nomear o que fica no runbook (topologia de operação com diagrama, superfície, variáveis, passos/verificação/ reversão): ele só enumerava proibições, e a migração revertida cortou junto o Mermaid de topologia que o próprio molde prescreve — regra que só diz o que sai é aplicada cortando demais. Registrada a armadilha do --8<-- (é pré-processador de linha: transclui dentro de bloco de código e de comentário HTML; escape é ;) em Templates. Runbook que linka continua conforme — transcluir é permissão, não obrigação. Decisão 0013.

  • Piso §6 — "o teste não reimplementa a lógica que atesta" (loop §6, feedback de app). A definição de pronto cobrava "teste proporcional ao risco" e já nomeava a fixture inventada como falso atestado, mas não o irmão dela: o teste que refaz no próprio corpo a conta da produção passa por construção — o expected deixou de ser oráculo e virou um segundo palpite da mesma cabeça que escreveu o código. Caso real: um teste de agregação somava as linhas no test e comparava com a soma do serviço, verde sobre uma agregação errada. O piso agora exige oráculo de fora (valor literal, saída capturada, invariante independente), e o ci-testes registra o teste de mutação (PIT) como ferramenta de diagnóstico sob demanda — não gate, pela mesma razão de "cobertura é visível, não bloqueante".

  • Constituição 0.20.2→0.21.0 — o kit de UI ganha o gate que faltava: checa-views.py (loop §6, feedback de app). O kit de UI foi o primeiro template rastreado executável (os demais são Markdown, ou Python com teste de regressão), e para ele o central não tinha guarda nenhuma: o manifesto atesta que a cópia do app é idêntica à do central (sha256), nunca que ela funciona. Foi exatamente essa fresta que deixou a 0.19.0 publicar um layout.html com dois th:fragment="navbar" homônimos — sha íntegro, --check verde, 500 em toda view de quem adotasse. O novo check é stdlib e offline (sem JVM): reprova fragment homônimo, chamada a fragment que o layout não declara, aridade divergente, chamada posicional contra fragment sem signature (o defeito da 0.19.2) e markup passado declarado fora do host do th:replace. Roda no ci.yml de todo app com view (tolerante: sem src/main/resources/views/, sai 0) e no CI do central contra templates/views/ — na origem, antes de publicar, que é onde o defeito da 0.19.0 teria morrido. Verificado contra o layout.html real da 0.19.0 (reprova) e contra as 38 views reais do integrador e do int-produtos-ecom (verde, sem falso positivo). Acompanha testa-checa-views.py (12 casos, central-only).

  • headComExtras(title, extras) no kit de UI — a tela que precisa de markup próprio dentro do <head> (típico <noscript><meta http-equiv="refresh"> de fallback sem JS, inválido e ignorado fora do <head>) não tinha lugar canônico e empurrava o conteúdo para o <body>. Irmão nomeado do head(title), como o navbarComMenu é do navbar: sem overload por aridade, e as telas que já chamam head('Título') seguem intactas.

Corrigido

  • A receita não dizia ONDE a página declara o markup que passa (~{::navMenu}): o th:replace substitui o elemento host inteiro — host e conteúdo somem do output. Declarado solto no <body>, o th:fragment renderiza duas vezes; o certo é aninhá-lo dentro do elemento que faz o replace, e isso só aparecia no exemplo para quem já soubesse. É silencioso (não dá 500, só sai errado na tela). Agora está no bloco de código da receita, no cabeçalho do layout.html, e o checa-views.py reprova.
  • th:fragment="styles" morto no <head> do kit — fragment vazio herdado do layout pré-kit do integrador na templatização da 0.19.0. Zero uso nos dois apps Micronaut, não documentado em lugar nenhum: sinalizava um slot que não entregava. Removido; quem precisa de markup no <head> usa o headComExtras.

0.25.1 - 2026-07-16

Adicionado

  • Constituição 0.20.1→0.20.2 — runbook de implantação vira molde, e o §2 ganha as três regras que o pior dia cobra (loop §6, feedback de app). O nível 5 promete "runbooks técnicos: deploy, recuperação, destrutivas", mas o único template era o runbook.md, de procedimento pontual (operação única, disparada por incidente, num app só) — quem precisava documentar subir um sistema não tinha base, e a diferença não é de tamanho, é de eixo: o procedimento responde "como executo esta operação"; a implantação, "como este sistema fica de pé, e como eu o desligo". Agora há templates/implantacao.md, irmão do runbook.md (não substituto): topologia de operação, superfície de operação, variáveis por servidor com os pares que têm de casar, passos, verificação, reversão.
  • Três regras no piso §2 (bullet Runbook) — cada uma de um defeito real que passou pela revisão humana num doc de implantação escrito sem base: (1) a Reversão enumera todas as vias e o que cada desligar isolado não para (sistema com webhook + varredura precisa da tabela caminho → efeito, com os caminhos que não funcionam marcados — kill switch não conferido contra o código é kill switch imaginário, e é lido no pior dia possível); (2) todo passo de Verificação declara o resultado esperado conferido no código — mesmo payload ≠ mesma versão: onde a chave-versão é bumpada por escrita (@DateUpdated, sem dirty-check), idempotência prova-se com uma escrita e vários ciclos do consumidor, nunca com duas; (3) valor de contrato externo sem fonte do outro lado é <PLACEHOLDER> + bloco "A confirmar" com o efeito de errar — fixture nossa não confirma contrato de terceiro (javadoc "ex.:", seed e whitelist concordam entre si porque descendem da mesma suposição). Valem para os dois moldes: as duas primeiras cobram seções que todo runbook já tem.

Corrigido

  • §2 ganha a metade que faltava da fronteira: "o livro não entra no runbook" — corolário simétrico do já escrito "o deploy não entra no livro". O doc que originou este feedback re-digitava três capítulos do livro (topologia-arquitetura, fluxo de eventos, contrato de entrada), contra §1.9 (um dono por fato) e §1.2 (o factual vem da fonte). Não é purismo: o contrato re-digitado longe do dono foi o que virou exemplo-que-mente. O molde novo linka o livro e escreve só o que é de operar.

Adicionado

  • Constituição 0.19.2→0.20.1 — o container do app vira artefato prescrito (loop §6, feedback de app: nasceu doc-only, virou código, passou em teste e e2e local e quebrou no deploy do Coolify por não ter Dockerfile). A plataforma nunca prescreveu container: todo o conhecimento vivia no registro "não pise nesta mina" (armadilhas de .dockerignore/.git/HEAD), e o registro "isto é o que você constrói" nunca foi escrito — coolify.md dizia "Build Pack: Dockerfile" tratando o arquivo como fato da natureza. Havia contradição interna: a §5 exige health check obrigatório, mas a Estrutura padrão (§3) não listava o artefato onde o HEALTHCHECK vive. E era assimétrico: flutter.md tinha receita, java-micronaut.md não citava Dockerfile em linha nenhuma — a stack que mais deploya era a sem receita. Agora: piso na §3 (app deployável leva Dockerfile + .dockerignore desde o 1º commit de código); templates rastreados e opcionais dockerfile-java + dockerignore-java; ## Deploy — o Dockerfile em java-micronaut.md; gate docker build no pré-flight do /xadm-release (degradado sem daemon, declarado no relatório); trilha "repo que era só doc e passou a ter código" em app-novo.md; decisão 0011. Motivo do gate: o ci.yml não builda imagem e o Coolify builda o Dockerfile do repo — era o único artefato que nenhum CI tocava, e a produção era a primeira a exercitá-lo.

  • Flutter §Deploy web — cache no nginx (loop §6, feedback de app). Receita nova: main.dart.js é no-cache, não cache longo — o Flutter Web não versiona URL de filho (verificado no build 3.44: buildConfig traz "mainJsPath":"main.dart.js" e o loader monta a URL sem query nem hash; o único ?v= é do flutter_service_worker.js, e a casa builda --pwa-strategy=none). Errar isso é invisível no deploy e mata o auto-update: o banner de "nova versão" aparece, o usuário clica e o browser serve o mesmo bundle do cache por até 30 dias. Regra + map de exemplo + os assets de nome fixo que também precisam revalidar (MaterialIcons-Regular.otf, sqlite3.wasm, powersync_db.worker.js) + curl -sI …/main.dart.js como verificação pós-deploy. Motivo de existir a receita: o bi-comercial corrigiu o bug em 2026-05-13 e o bi-transporte ficou dois meses com o comentário oposto e max-age=2592000 em produção — o central não tinha dono do assunto.

Alterado

  • SENTRY_DSN é o env canônico do DSN em toda stack (antes GLITCHTIP_DSN). É o nome que o SDK do Sentry lê do ambiente por convenção (Java e Dart) e o GlitchTip é Sentry-compatível, então o nome canônico elimina o código que existia só para traduzir env. A constituição mandava GLITCHTIP_DSN, mas metade dos repos Java (integrador, int-produtos-ecom, bi-transporte-xls) e todo o Flutter já usavam SENTRY_DSN — a mudança ratifica a maioria. Vale igual no Flutter (--dart-define=SENTRY_DSN) e é o nome que o /xadm-setup injeta no Coolify (exceção glitchtip.dsn → SENTRY_DSN na tabela ENVS_CANONICOS do broker). Atenção — o rename é SILENCIOSO, não barulhento: trocar o nome no Coolify sem o código já ler o novo não dá erro — o ${…:-} resolve para vazio, o appender vira no-op e o app sobe normal, enquanto todo erro de produção para de ser reportado sem sinal nenhum. Ordem segura: código primeiro (com fallback ${SENTRY_DSN:-${GLITCHTIP_DSN:-}}), deploy, aí o rename no Coolify, aí remove o fallback. A injeção do broker é upsert: reprovisionar cria SENTRY_DSN e deixa o GLITCHTIP_DSN órfão no recurso — apagar na mão.

Corrigido

  • Cache mount do Gradle no Dockerfile: id default = target + sharing default = shared (achado ao dogfoodar o template novo — buildá-lo contra um app real em vez de publicá-lo por inspeção). Os dois apps Java da casa usam --mount=type=cache,target=/root/.gradle bare; como o id de um cache mount default para o próprio target, todos os apps Java dividem um único cache no servidor do Coolify, e o sharing default shared ("can be used concurrently by multiple writers") é justamente o que o Gradle não tolera. Dois deploys concorrentes — ou um build morto que deixou lock stale — falham com Timeout waiting to lock journal cache (/root/.gradle/caches/journal-1). It is currently in use by another process, intermitente e com cara de bug do app. Reproduzido, não inferido. Template usa id=gradle-<slug> + sharing=locked (o que a doc do Docker prescreve para o apt, pela mesma razão); nota em java-micronaut.md §Deploy. Migração oportunista nos apps existentes.

  • .dockerignore não é .gitignore — a diferença é silenciosa e um dos padrões quebraria o build. Verificado empiricamente (Docker 29.5), contra fonte que afirmava o contrário: o Docker casa padrões com filepath.Match do Go, onde * não cruza /. Consequências que os repos atuais carregam sem saber: build bare exclui só a raiz (sub/build/ viaja pro daemon — inócuo em single-module, mina armada ao modularizar), e **/*.jar quebraria o build ao excluir o gradle/wrapper/gradle-wrapper.jar (o gradlew morre com "Could not find or load main class org.gradle.wrapper.GradleWrapperMain"). O template usa **/build e mantém *.jar raiz-only de propósito, com o porquê escrito. A exceção !docs/app.json do item 79 foi verificada de fato funcionando (e só funciona depois de docs: vence a última linha que casa, não a mais específica).

  • Constituição 0.19.1→0.19.2 — kit de UI: layout.html declarava dois fragments navbar homônimos (loop §6, feedback de app). O layout tinha th:fragment="navbar" e th:fragment="navbar(menu)", mas o Thymeleaf resolve fragment por nome e não faz overload por aridade (confirmado na doc oficial) → as duas chamadas que a receita ensinava quebravam no render (500): ~{layout :: navbar} casava a variante com signature ("Error resolving fragment: ${menu}") e ~{layout :: navbar(~{::navMenu})} casava a sem signature ("Signature navbar declares no parameters, but fragment selection did specify parameters"). Qualquer app que adotasse o kit da 0.19.0 batia nisso. A variante com menu virou navbarComMenu(menu) — nomes distintos, chamadas posicionais válidas nos dois lados, sem th:if no fragment (que cairia na armadilha de precedência th:replace(100) < th:if(300) e contrariaria o corolário de "duas superfícies, dois fragmentos" já normatizado). Receita do Java/Micronaut §UI corrigida; apps re-derivam o kit via /xadm-docs.

  • Constituição 0.19.0→0.19.1 — checa-nav casava globs com fnmatch, não com o formato .gitignore (loop §6, feedback de app). Os padrões de not_in_nav:/exclude_docs: seguem o formato .gitignore (doc do MkDocs), e o script os casava com fnmatch — semânticas diferentes, divergindo em três frentes: barra inicial (/privado/* nunca casava → falso positivo, gate vermelho num exclude legítimo — o caso do feedback), barra final (privado/ não casava em nível algum — é o exclude_docs: do próprio central, inócuo só porque ainda não há .md sob privado/) e * cruzando / em padrão ancorado (rascunhos/*.md absolvia rascunhos/mais/b.mdfalso negativo, órfão real passando). Trocado por um mini-matcher .gitignore em stdlib (o check roda no gate de código do app, onde não há mkdocs nem pathspec).
  • checa-nav: menção em comentário do mkdocs.yml valia como declaração de nav: (mesmo feedback). O script varria o YAML cru com regex ([\w./*\-]+\.md), então um .md citado num comentário absolvia o arquivo órfão — falso negativo que escondia o falso positivo acima. Comentários agora são removidos antes do regex (preservando âncora pagina.md#secao, que não é comentário).
  • testa-checa-nav.py (novo, central-only): regressão do checa-nav em 9 casos versionados — os 4 bugs acima reprovam a versão anterior. Roda no CI (build-site.yml) e no pré-flight da /xadm-release, como o testa-valida-frontmatter.

0.24.0 - 2026-07-16

Adicionado

  • Constituição 0.18.11→0.19.0 — UI unificada para apps server-render (loop §6, feedback de app). A constituição regia doc e engenharia mas não tinha convenção de UI: cada app que renderiza HTML no servidor (Micronaut Views/Thymeleaf) — telas de admin/ops/dev, mesmo internas e atrás do gate de auth do Coolify — reinventava o visual (integrador padronizado × tradutor ecom com <table border="1"> cru), drift que só se pega no olho. Piso novo no §5 (UI dos apps): todo app server-render segue o layout padrão X-Adm (fragment base único head/navbar/scripts, Bootstrap 5, header escuro com logo, idiomas da casa table-striped/badge/alert) na paleta única do xadm.css; o app só escreve o conteúdo de cada tela. Kit rastreado opcional no manifesto (templates/views/layout.html + custom-theme.css + logo.png + favicon.ico; sincroniza pela /xadm-docs, ausente em app headless/Flutter não é defasagem) + item de conformidade §3b da /xadm-docs (tem views mas não usa o layout → não-conformidade). Detalhe operável + snippet static-resources em engenharia/java-micronaut.md §UI; re-derivado limpo na paleta canônica (o kit do integrador usava #0066CC, cor errada); decisão 0010.
  • Constituição 0.18.10→0.18.11 — espelho fiel ao X-Adm (nível de coluna) (loop §6, feedback da integração PIED). A integração PIED promoveu chaves do vocabulário do parceiro (codigo_alt, x_ped) a identidade de 1ª classe na tabela-espelho; a §Fronteiras só regia o prefixo de tabela, nada regia a identidade de coluna dentro do espelho. Piso novo no §8 (ao lado de owner-writes): a tabela-espelho modela a entidade do X-Adm, não a do parceiro — identidade em coluna nativa (conferida contra a spec de entidades do ERP), campo de origem externa entra prefixado (<origem>_) e só como rastreabilidade, nunca chave/join. Detalhe operável + tabela de coluna em documentacao/integracao.md §Fronteiras; eco server-side em engenharia/java-micronaut.md §Banco; decisão 0009.
  • Dois gotchas de stack no java-micronaut.md (loop §6, feedback de app; engenharia-only, sem bump). (1) §Armadilhas: @Client config-gated — declarar micronaut.http.services.<id>.url cria um ServiceHttpClientConfiguration eager (@EachProperty) que quebra o startup do contexto inteiro se a URL estiver vazia (Failed to inject value for parameter [url]; sintoma = N @MicronautTest em massa no NettyHttpServer.start/beforeAll). Cliente HTTP só-em-alguns- deploys: @Client("${prop.url}") na interface + BeanProvider<Client> (lazy), assim o bean nem nasce. (2) §Banco: chave-de-mudança de espelho multi-writer vive no banco (trigger), não no appupdated_at por trigger Postgres (BEFORE INSERT OR UPDATE, bump só em IS DISTINCT FROM) cobre todos os escritores (apply, admin CRUD, PowerSync) num lugar; coluna trigger-managed não se mapeia na entidade (Micronaut Data faz UPDATE só do mapeado → null-wipe no update).
  • Flyway em Postgres compartilhado — app secundário exige baseline (loop §6, feedback de app; engenharia-only, sem bump). §Banco do java-micronaut.md: com a história por app, o segundo app sobe com a sua tabela de histórico ainda inexistente contra um schema não-vazio (tabelas do app dono já lá) → o Flyway aborta ("Found non-empty schema(s) without schema history table"). Cura: baseline-on-migrate: true + baseline-version: 0 — o primeiro deixa o Flyway marcar o schema como linha-base em vez de abortar; o segundo faz a própria V1 do app rodar (o default 1 pula a V1 do secundário silenciosamente). Só no app secundário; o dono do schema sobe do zero.

0.23.7 - 2026-07-14

Adicionado

  • Higiene do .claude/settings.json vira norma da casa (engenharia/ferramentas.md, com ponteiro no app-novo.md): o arquivo versionado leva só o compartilhado (hooks + additionalDirectories relativo + allow-list de padrões largos que absorvem os comandos comuns); grants pessoais/de-máquina vão para .claude/settings.local.json gitignored. Sem isso o allow-list incha a cada sessão e o git commit --amend resultante troca o hash sob a tag, soltando a release. O template gitignore-flutter passa a ignorar o settings.local.json.
  • Estilo terso (caveman) ativado no repo central via hook SessionStart (.claude/caveman.sh) — dogfood do padrão que agentes.md/app-novo.md/ferramentas.md já prescreviam; regra de higiene de arquivos afiada em ferramentas.md ("Bash executa, não lê" + blocklist sed/ls -la/grep -rn).

Corrigido

  • Typo no .gitignore (.claude/.settings.local.json.claude/settings.local.json) que deixava os grants pessoais fora da proteção do repo (só o ignore global da máquina cobria).

0.23.6 - 2026-07-14

Adicionado

  • Constituição 0.18.9→0.18.10 — o fechamento passa a recomendar /compact depois do commit (pedido do Gustavo; altitude decidida por AskUserQuestion = skill + constituição §6). O /x-documentar é o passo que persiste o durável em docs/, então compactar o contexto ao fim do ciclo recupera tokens sem perda (linha de economia dos itens 56/57/66). A ordem importa: commit antes do /compact, senão a mensagem pronta pode ir embora no resumo e o dev ainda não salvou. Bullet do fluxo recomendado no §6 da constituição + item 4 no fechamento (§5) da skill /x-documentar (template rastreado → re-carimbo + cópia dogfood re-derivada). Bump PATCH.
  • engenharia/java-micronaut.md §Armadilhas (loop §6, feedback de app): Thymeleaf bloqueia expressão String em atributo de evento (th:onclick/th:onload/th:on*). Por segurança (defesa contra injeção de JS via dado de usuário), o Thymeleaf 3.x só aceita nesses atributos expressão que retorna número ou boolean → String lança TemplateProcessingException ("Only variable expressions returning numbers or booleans are allowed…") no render, com o build verde. Padrão da casa p/ linha/ card clicável: dado num data-* (th:attr="data-href=@{/rota/{id}(id=${x})}") + handler em JS no rodapé — nunca th:onclick com a URL. Nova armadilha na família de view server-side (irmã do record/OGNL e do th:replace). Bônus (corolário atado ao bullet de precedência th:replace× th:if, decisão do Gustavo — AskUserQuestion): duas superfícies de UI distintas (chrome público × navbar de operador) = dois arquivos de fragmento de layout separados, não um layout único com th:if no menu. Engenharia-only, sem bump (java-micronaut.md não é rastreada).
  • engenharia/java-micronaut.md §Armadilhas (loop §6, feedback de app): ViewModelProcessor + Map.of() do controller = HTTP 500 só nas rotas que devolvem imutável. Um ViewModelProcessor injeta dado transversal no modelo de toda view (usuário/tenant/versão no layout — padrão layout.html
  • GlobalViewModel do molde do integrador) via model.put(...); se o controller devolveu um Map.of(...) (imutável, comum no ramo "não encontrado"), o put estoura UnsupportedOperationException → 500, só naquelas rotas. Regra: view controller sempre devolve modelo mutável (LinkedHashMap), nunca Map.of. Guarda barata: teste GET numa rota de not-found esperando 200. Nova armadilha na família de view server-side (irmã do record/OGNL e do th:replace), engenharia-only, sem bump (java-micronaut.md não é rastreada).
  • engenharia/java-micronaut.md §Erros e logging + §Armadilhas (loop §6, feedback de app): cliente HTTP + config vazia = 500 + registro preso. URI montada de config (baseUrl + rota) com base vazia vira URI relativa → HttpRequest.newBuilder lança IllegalArgumentException (não a exceção de domínio) → escapa do catch → 500; pior, se a máquina de estados marcou o registro "em voo" (ENVIANDO) antes da chamada, ele fica preso sem transição de saída. Dividido em dois donos (decisão do Gustavo, AskUserQuestion): norma durável de resiliência em §Erros e logging (validar a montagem da chamada → exceção de domínio tratável; catch de chamada externa largo o bastante pra RuntimeException inesperada, garantindo transição pra estado terminal em qualquer exceção) + a armadilha concreta em §Armadilhas apontando pra norma. Engenharia-only, sem bump.
  • Constituição 0.18.8→0.18.9 — armadilha "Dockerfile lê docs/app.json ⇒ precisa da exceção !docs/app.json no .dockerignore" (loop §6, feedback de app; verificado no .dockerignore do integrador, que exclui docs). A ponte de config da Central de Apps tem duas metades que viajam no mesmo PR: o Dockerfile ler docs/app.json (Flutter via jq--dart-define em build-time; um servidor via COPY→leitura em runtime) e a exceção no .dockerignore — separar quebra o deploy (arquivo fora do contexto de build). Dono stack-neutro: infraestrutura/coolify.md, ao lado da gêmea "não leia .git/HEAD no build", com o contraste preciso (aqui a negação !docs/app.json resolve — o arquivo é committado e está no contexto; lá o .git nem chega ao contexto). Cross-link da receita jq docs/app.json em engenharia/flutter.md. A /xadm-setup passo 5 (que manda "crie a ponte") passa a exigir as duas metades → bump PATCH e re-carimbo do xadm-setup-skill.md. Decisão do Gustavo (AskUserQuestion): altitude = também a skill rastreada.
  • engenharia/powersync.md §Auth (loop §6, feedback de app PowerSync): a §Auth passa a distinguir dois modos de consumidorapp com usuário real (JWT do usuário via JWKS do auth, ou jwks_uri do Google no Firebase) vs cliente máquina-a-máquina (o cliente Java do ERP, os reatores — sem humano), que nasce self-signed + JWK inline: o cliente assina o próprio JWT com key privada em env e o PowerSync valida contra o JWK público inline — o mais simples e sem peça nova (sem broker, sem IdP), reservando Firebase/pAbast para quem tem usuário de verdade. Casa com três normas já existentes (Kerckhoffs em seguranca.md §Segredos, inline > jwks_uri da própria §Auth, reusar-antes-de-inventar). A pegadinha do jwks_uri (timeout ~3s + NAT hairpin → falha intermitente, recorrente em produção) já estava documentada; ganhou nota de que vale para os dois modos e de que o self-sign já nasce inline. Ressalva anti-confusão: este M2M ≠ o M2M do broker de setup (lá quem assina é o auth; aqui, o próprio cliente). Engenharia-only, sem bump (powersync.md não é rastreada). Decisões do Gustavo (AskUserQuestion): altitude engenharia-only (não subir ao §8) e só a §Auth (sem eco na seguranca.md, que já cobre Kerckhoffs).

0.23.5 - 2026-07-13

Adicionado

  • engenharia/java-micronaut.md (loop §6, feedback de app — três gotchas de stack Micronaut/Thymeleaf): (a) §Armadilhas — o ERROR Failed to inject … jsonMapper (JsonMessageHandler) no fim de uma run multi-classe @MicronautTest é artefato de teardown (o Micronaut derruba o contexto compartilhado e loga a injeção de um bean interno num contexto já desmontado), não bug: se a suíte fecha verde, não caçar — mesmo balde do falso-0% do JaCoCo e do Test Resources órfão. (b) §Armadilhas — Thymeleaf: th:replace/th:insert (precedência 100) rodam antes de th:if/th:unless (300), então th:if no mesmo tag de um th:replace não segura (o elemento já foi substituído quando o th:if seria avaliado); cura = th:if num elemento pai (ou <th:block>). (c) §Testes — costura para testar controller cuja ação chama serviço com HTTP externo: o HttpClient injetado por DI (base-url vazia em teste) aponta pro servidor embutido, não pra porta dinâmica do WireMock → teste o serviço com client construído à mão na porta do WireMock e o controller só nos ramos sem rede. Placement de (a) decidido pelo Gustavo (§Armadilhas, a família "parece bug, não é"). Sem bump (java-micronaut.md não é rastreada).

  • engenharia/java-micronaut.md §Armadilhas (loop §6, feedback de app): record no modelo do Thymeleaf estoura Property … not found. Micronaut Views usa o Thymeleaf standalone, cuja linguagem de expressão é o OGNL, que resolve propriedade por getter JavaBean (getFoo()); um record gera acessor foo(), não getFoo(), então ${obj.foo} falha no render (erro de template, não null). Saídas: passar um Map no modelo ou invocar o método (${obj.foo()}). Sem bump (java-micronaut.md não é rastreada). Fora (decisão do Gustavo, não normatizado): "preferir cliente REST mão-livre (JDK HttpClient) a @Client declarativo" — é consistência interna de 1 app, não prática da casa (≥2 repos); @Client é idioma Micronaut válido.

  • Constituição 0.18.8 — piso no §6 (Definição de pronto): contrato de entrada entre componentes NOSSOS (skill/cliente → endpoint first-party, ex. o broker POST /api/setup/provision que o /xadm-setup consome) tem os campos obrigatórios travados nos DOIS lados — o cliente declara o contrato e o provedor tem teste que rejeita payload faltante (400 legível, não 500). Sem o par, driftam em silêncio: o guia dizia (app_id, feature), o broker passou a exigir mais → 500 em produção em vários apps antes de alguém notar (loop §6, feedback de app). Distinto do que já existia ("fixture de API externa é capturada, não inventada" = shape de resposta de terceiro; este = contrato de entrada first-party não-verificado no provedor). Detalhe cross-stack em engenharia/ci-testes.md §Definição de pronto (bullet novo, ao lado da fixture capturada); contrato operável do broker em documentacao/central-de-apps.md (bloco de identidade do app.json: app_id, feature, grupo, cliente_id); síntese enganosa (app_id, feature) corrigida no template rastreado xadm-setup-skill.md (l.47) e no diagrama de central-de-apps.md. Bump PATCH 0.18.7→0.18.8 (xadm-setup-skill.md re-carimbado). Handoff para o app auth (§6, Gustavo colar lá): o broker precisa do teste que rejeita /provision sem os campos obrigatórios.

  • engenharia/java-micronaut.md §Erros e logging + engenharia/seguranca.md §Validação de input (loop §6, feedback de app): quando o corpo problem+json carrega um code de máquina que um consumidor NOSSO ramifica (ex. a Central lê o code do broker), esse discriminador tem de ser uniforme para toda a falha da mesma classe — a armadilha é o Bean Validation na borda (@Valid @NotBlank) produzir um code derivado do status (BAD_REQUEST genérico) enquanto uma checagem no service produz o code próprio da exceção de domínio, deixando o consumidor com metade das faltas de campo obrigatório num code e metade noutro. Norma: conserte o contrato, não o placement — mantenha o @Valid na borda (norma da seguranca) e faça o ErrorResponseProcessor de ponto único carimbar um code estável também nas falhas de Bean Validation (com a lista de campos). Refina o lado provedor do contrato de entrada travado dos dois lados (item 75): não basta rejeitar faltante com 400 — o 400 consumido por máquina precisa de code uniforme. Sem bump (java-micronaut.md/seguranca.md não são rastreadas). Handoff para o app auth (§6, Gustavo colar lá): validar o campo obrigatório de contrato no mesmo lugar que os demais (ou carimbar o code de máquina no processor também para o Bean Validation) — hoje campos validados na borda saem com code derivado do status, inconsistente com os validados no service que a Central consome.

  • engenharia/java-micronaut.md §Armadilhas (loop §6, feedback de app): a armadilha do Test Resources órfão ganha um segundo gatilho além do SIGTERM — rodar o gate com --no-daemon e apagar build/ entre execuções órfã o serviço de TR (sem daemon ele não sobrevive à JVM efêmera; o rm -rf build/ remove os arquivos de descoberta da porta) → mesma falha "Test resource service is not available"initializationError em massa, que parece bug de código mas é infra. Lado da prevenção: rodar o gate com daemon (default) e não rm -rf build/ no meio de uma sessão de testes; se travar, o sintoma é service not available, não o código. Sem bump (java-micronaut.md não é rastreada).

Corrigido

  • engenharia/java-micronaut.md §Observabilidade (loop §6, feedback de app Java): a receita do SentryAppender colocava o <dsn> flat no appender, mas em io.sentry:sentry-logback 8.x o SentryAppender só expõe setOptions(SentryOptions)dsn é propriedade do SentryOptions, não do appender. <dsn> fora de <options> não casa com setter nenhum e o logback ignora em silêncio (só um WARN no status interno; build verde) → DSN nunca setado → no-op invisível, e o erro real some em produção sem ninguém notar. Corrigido para <options><dsn>${GLITCHTIP_DSN:-}</dsn></options> (o <minimumEventLevel> é setter do appender e segue flat), com a nota do porquê e do porquê a rota /test/glitchtip existe (pega justo esse buraco). Confirmado na doc oficial do Sentry (logback). Também ajustada a prosa da §Níveis de log que dizia "DSN no próprio appender". Sem bump (java-micronaut.md não é rastreada).

0.23.4 - 2026-07-11

Adicionado

  • Constituição 0.18.7 — regra de layout de diagrama no §5: fluxograma Mermaid é TB (vertical) por padrão. A página tem largura fixa e rolagem vertical infinita, então em TB cada linha usa a largura toda e o texto fica legível sem zoom; em LR o diagrama cresce na horizontal e aperta as caixas. Norma pede labels curtos e direction TB também dentro dos subgraph; LR/RL só para pipeline curto e linear. Enforcement: o lint-mermaid.mjs (rastreado) agora falha o build num flowchart LR/RL com mais de 6 caixas, pedindo TB — escape hatch para o pipeline curto legítimo é um comentário %% lint-mermaid: LR-ok no bloco. Bump PATCH 0.18.6→0.18.7. Loop §6 (feedback de app).

0.23.3 - 2026-07-10

Corrigido

  • Constituição 0.18.6 — o gate de formatação Dart checava reescrevendo: o comando da casa era dart format --set-exit-if-changed ., e o default do dart format é --output=write (grava em disco). O gate saía 1 e consertava os arquivos de passagem — rodar de novo dava verde, o vermelho parecia transitório e a correção ficava não-commitada (o git add do release leva só manifesto + CHANGELOG), de modo que o CI, com checkout limpo da tag, reprovava o que "passou" na máquina. Reabria exatamente o furo que a 0.18.5 fechou, e era invisível no CI (checkout efêmero). Agora o comando canônico é dart format --output=none --set-exit-if-changed . (Flutter e Dart) em todos os pontos que o enunciam: /xadm-release, /x-implementar (+ reference Flutter), /x-planejar, /xadm-meta-audit-work, ci.yml, analysis_options.yaml, engenharia/flutter.md, engenharia/ci-testes.md e documentacao/app-novo.md. Princípio durável novo em ci-testes.md §Definição de pronto: verificador não muta a árvore de trabalho — gate é check, nunca fix (vale para spotlessApply/ktlintFormat do lado Java; use spotlessCheck/ktlintCheck, que o ./gradlew check já agrega). Corolário: se o gate mudou arquivo, o gate estava errado. O bloco Flutter do /xadm-release ganhou também a nota do prefixo fvm em repo com .fvmrc (dentro do container ci-flutter:<v> o SDK está no PATH e o prefixo não se usa). Loop §6, app Flutter. Bump PATCH 0.18.5→0.18.6.

  • Constituição 0.18.5 — o pré-flight do /xadm-release roda o gate de CÓDIGO da stack, não só o de docs (loop §6, app Java). O template enumerava os gates de docs por nome e tratava o código por uma frase genérica ("rode todos os checks do CI") — e o checkstyle, que só dispara dentro do ./gradlew check e não é coberto pela análise estática feita lendo o diff, escapava até o push da tag (CI vermelho com a tag criada, exigindo release de correção). Agora cada bloco de stack em Particularidades traz a linha Gate de código (Java ./gradlew check --no-daemon; Flutter dart format --output=none --set-exit-if-changed . && flutter analyze && flutter test; Node npm run lint && npm test) e o pré-flight tem dois bullets nomeados — código e docs —, vermelho em qualquer um = bloqueador. Máquina sem Docker/Testcontainers roda o degradado (checkstyleMain checkstyleTest) e o relatório final declara o gate degradado. Eco da norma em engenharia/ci-testes.md §CI de código. Bump PATCH 0.18.4→0.18.5.

0.23.2 - 2026-07-08

Adicionado

  • Constituição 0.18.4 — princípio "fórmula de derivação de token é segredo se não há key separada" (loop §6 do auth) em engenharia/seguranca.md §Segredos: se um token de auth é derivável de uma fórmula sem um segredo à parte, a fórmula É o segredo — não vai em javadoc/comentário em claro (quem lê o fonte cunha um token válido = bypass); o certo é Kerckhoffs — derivar por HMAC com a key em env/secret (algoritmo público, só a key secreta).
  • engenharia/flutter.md §Testes — verificação visual headless (loop §6, bi-transporte): a receita de screenshot (kScreenshotMode + seed InMemoryAppDatabase) dobra como loop de verificação de mudança de pixel — renderizar pro PNG e ler a imagem confirma a mudança sem app rodando.
  • engenharia/flutter.md §Arquitetura (loop §6, bi-transporte): padrão "extrair side-effect de serviço de estado — delegação, não listener". Quando o estado rastreado (intenção do usuário) ≠ o ValueListenable exposto (efetivo/derivado, com ajustes automáticos), um listener emite eventos espúrios; o serviço delega observer.onChange(prev, next) no ponto da mudança de intenção e move a máquina (buffer/debounce/SDK de analytics) para fora. Ref. FilterAnalyticsObserver.
  • Constituição 0.18.3 — disciplina "caracterização precede refactor" (loop §6): antes de virar tarefa de plano um "unificar/deduplicar N classes de mesmo nome", ler os corpos e confirmar a identidade (caso real: 6 variantes _Measure que pareciam 1). Em engenharia/ci-testes.md §Definição de pronto e no /x-desenhar (§2 explorar — design-time).

Alterado

  • /xadm-setup (constituição 0.18.4, loop §6 do auth): a nota de auth M2M passa a proibir derivar o token de serviço da fórmula mesmo com o fonte do auth à mão (o filtro de validação à vista) — peça o token ao usuário; computar da fórmula é bypass, não conveniência. Template rastreado → bump PATCH 0.18.3→0.18.4.
  • engenharia/java-micronaut.md (loop §6, refinamentos verificados no integrador): corrige a receita da armadilha Test Resources órfão (era 0.23.1) — ./gradlew --stop sozinho não resolve (a task internalStartTestResourcesService fica UP-TO-DATE); o remédio universal é apagar o estado stale (rm -rf .micronaut/test-resources .gradle/configuration-cache). Nova nota no §Guarda de fronteiras: a guarda de arquitetura é bytecode — não vê dependência via constante static final inlinada (limite conhecido, não violação a caçar). Expande a nota configuration-cache-safe (sem capturar layout/project; ler o ÚLTIMO <counter> do XML do JaCoCo).
  • engenharia/flutter.md §Piso: reforça que os lints de segurança assíncrona (unawaited_futures/ cancel_subscriptions/close_sinks) pegaram 3 bugs reais na adoção — ligar cedo (na caracterização), não no fim.

0.23.1 - 2026-07-08

Adicionado

  • Princípio de engenharia "reusar a infra da casa antes de inventar mecanismo" (loop §6): ao desenhar transporte/gatilho entre serviços, confirmar a infra que já existe (PowerSync acoplado à fonte da verdade) antes de propor um mecanismo novo — evita decisão auto-contraditória. Em engenharia/index.md §Princípios.
  • Constituição 0.18.1 (loop §6) — cobertura de código: política + JaCoCo amarrado ao Java. A política (visível não bloqueante por norma; piso bloqueante opt-in por app) entra em engenharia/ci-testes.md §Definição de pronto; a tech em engenharia/java-micronaut.md §Testes, com a pegadinha crítica: JaCoCo <0.8.15 não instrumenta Java 25 (class major 69) → relatório válido na aparência mas vazio (falso 0% silencioso) — amarre a toolVersion ao Java (Java 25 → ≥0.8.15) + nota configuration-cache-safe. Novo item de conformidade no /xadm-docs (§3b) checa isso.
  • Armadilha (loop §6) em engenharia/java-micronaut.md §Armadilhas: gate morto por SIGTERM órfã um serviço na porta (daemon do Gradle ou Micronaut Test Resources) → initializationError em massa na run seguinte; remédio ./gradlew --stop + matar o órfão (e a norma da casa é o container singleton, que o Ryuk reapa).
  • Constituição 0.18.2 — disciplina de tokens propagada aos apps. O claude-regras.md (CLAUDE.md que os apps herdam) ganha o ponteiro de gate-discipline (gates bare / rtk err / sem pipe-git -C-2>&1; a frugalidade-na-fonte é o portável sem rtk) — antes só cobria caveman+enxuto, e o vazamento medido (rtk discover: ~561K tokens/30d) vivia nos apps. Allow-list do central ampliada (rtk read/grep/ls/find/wc/git diff).

0.23.0 - 2026-07-07

Adicionado

  • Constituição 0.18.0 — cliente_id é a chave canônica do tenant (loop §6, decisão 0008). Desconfla o cliente (rótulo de exibição) do cliente_id (chave clientes.cliente_id, minúscula) que a plataforma vinha derivando do display — a raiz de um incidente. Campo cliente_id novo no templates/app.json (obrigatório quando grupo=cliente); a /xadm-setup lê a chave, valida contra o catálogo do auth (fail-closed) e nunca deriva; guarda offline no valida-frontmatter (rejeita cliente_id malformado — o incidente) com fixtures versionadas (incidente + happy-path); norma em §7 e central-de-apps.md.
  • Constituição 0.18.0 — Plataforma de Integração vira norma central (§8), no molde do §7 (decisão 0007). Nova seção §8 (norma curta: organiza-se por shape; taxonomia hub/vertical/reator/app consumidor, ortogonal ao grupo do §5; owner-writes; transporte por direção; PowerSync bidirecional; bi-commons); página de detalhe documentacao/integracao.md (4 shapes, fronteiras, transporte); tech engenharia/powersync.md (connector, write-back, JWKS inline, edition:3, callback-200); invariante owner-writes no §Banco do java-micronaut.md; 7 verbetes no glossário (shape, hub, vertical, reator, barramento, owner-writes, bi-commons). O desenho concreto/volátil (roadmap, D0–D13) migrou para a arquitetura.md publicada no repo do integrador — a §8/página linkam, não copiam.

Alterado

  • Deploy do site volta ao auto-deploy do Coolify — o job deploy gated pelo CI (v0.22.0, faixa 3) foi revertido: exigia auto-deploy desligado no painel + os secrets COOLIFY_WEBHOOK_URL/ COOLIFY_API_TOKEN, que não foram configurados (o job falhava no push com secret ... ausente). Por ora o Coolify auto-deploya no push e a falha do CI avisa no Telegram (webhook nativo da org, Forgejo ≥12); o deploy gated fica como melhoria futura (job comentado no build-site.yml; ver infraestrutura/coolify.md).

0.22.0 - 2026-07-06

Adicionado

  • Faixa 3 da auditoria (constituição 0.17.36): (a) deploy gated pelo CI — o build-site.yml ganha o job deploy (needs: validar, só push em master) disparando o webhook do Coolify; CI vermelho = site antigo no ar (antes o auto-deploy ia pro ar com o CI vermelho; os dois modelos documentados em infraestrutura/coolify.md; requer auto-deploy desligado no painel + secrets COOLIFY_WEBHOOK_URL/COOLIFY_API_TOKEN). (b) Fábrica de imagens: build-push.sh ganha smoke test pré-push (java -version/ flutter --version/toolchain da base — imagem quebrada não entra no registry) e isolamento de falha por item (upstream quebrado de uma stack não bloqueia o rebuild das outras; resumo das falhas no fim, exit 1). (c) references/docs.md nas 5 skills x-* com references — a stack do próprio central (concerns de entrevista/spec/refino/ plano/execução para repo MkDocs: slug/redirect, dono do fato, satélites, artefato rastreado → bump, gate docs completo); 5 novos rastreados no manifesto.

  • CI do central = pré-flight nas duas direções: build-site.yml ganhou checa-nav.py (órfão de nav não falha o --strict — foi assim que um órfão real nasceu), valida-frontmatter.py docs/ e o publica-versao.py --self-test (grátis, stdlib).

  • sync-apps.sh: guarda de slug ([a-z0-9-]) nos nomes vindos do bucket — a key de escrita é única da org; slug malicioso/acidental com ../, espaço ou aspas podia virar traversal no docroot, quebrar o loop ou corromper o index.json de todos os apps.
  • /x-documentar: antes de apagar o andaime .ia/, confere git log -- .ia/NNN-* — arquivo nunca commitado (ciclo inteiro numa sessão) não é apagado, entra no commit do ciclo (senão "o histórico fica no Git" era promessa falsa e o rastro L# se perdia).
  • /xadm-release: disable-model-invocation: true no frontmatter — só o usuário invoca a única skill autorizada a commitar/pushar (fecha o vetor de release não-comandado, REGRA Nº 2).

  • Constituição 0.17.31: piso "saída do agente enxuta por default" na §6 — corta prosa conectiva e status óbvio (gate verde não se narra; nomeia-se só o que falhou), não re-descreve o que o diff/tool já mostram nem ecoa a escolha do usuário, e a prosa do fechamento §6 é terse (o literal — commit + linha §6 — não). Nunca comprime o carve-out. Vale com ou sem rtk/caveman. Detalhe e exemplos de mensagens recorrentes em engenharia/agentes.md (nova seção "Status e fechamento — nomeie só o que falhou").

Alterado

  • Constituição 0.17.36 — consolidação textual SEM mudança de norma (§6, §1.9, §2): o bullet "Definição de pronto" (27 linhas, 4 níveis de parênteses) virou 3 sub-bullets com o racional movido para ci-testes.md (que ganhou os bullets "deferir é custo × valor" e "fixture capturada" na seção de detalhe); "No CI (código)" enxugado com a fidelidade-ao-artefato apontando pro dono; §1.9 estruturado em 4 consequências nomeadas (andaime / segredo / código×doc / um-fato-um-dono); §2 ganhou subseções navegáveis (livro, nav+resumo, conteúdo mínimo); o cabeçalho deixou de prometer "documento curto e estável" e passou a dizer o que é (o piso; detalhe nas áreas).
  • engenharia/flutter.md §Específico reorganizado por tema (Build e versão do SDK / Config e Central de Apps / Observabilidade / Receitas) — era sedimento de feedbacks; bullets intactos.

  • Faixa 2 da auditoria — o "miolo do código" vira norma escrita (constituição 0.17.35; destilado dos pilotos com leitura autorizada: auth, bi-transporte-xls, bi-comercial-xls, bi-transporte, bi-comercial, authui):

  • Arquitetura v0.1 por stack: engenharia/flutter ganha §Arquitetura (layout feature-first, taxonomia de DI get_it/watch_it com lazy+dispose+dependsOn, estado no manager como valor observável, command_it, como nasce uma feature, variações declaradas) e engenharia/java-micronaut idem (package-by-feature travado por ArchUnit, constructor injection puro, controller fino, record @Serdeable vs @MappedEntity, @ConfigurationProperties, nomes pt-BR citando decisões).
  • Erros e logging por stack: exceção tipada na borda + erro-como-valor + trio loading/vazio/erro + AppLog com breadcrumbs/tags (Flutter); HttpStatusException + RFC 7807 num ponto único + semântica ERROR/WARN/INFO consciente do SentryAppender + logback com tuning comentado (Micronaut). Gap de request-id declarado como pendência, não fingido como prática.
  • Testes e fixtures: convenção golden-master datada com receita de captura no javadoc e anonimização obrigatória; WireMock com shape capturado (§6); Testcontainers com container compartilhado pinado à versão do deploy; unit×integração por environment (Micronaut) — e in-memory DB com DDL de produção, builders, seams nomeados, pushNewScope, teste de contrato do app.json (Flutter).
  • engenharia/seguranca.md (nova página): authn/authz fail-closed com tri-estado, tenancy pela claim (servidor decide), comparação em tempo constante, validação jakarta obrigatória em request novo, client-grade ≠ segredo, checklist do revisor.
  • Banco (Postgres compartilhado) em java-micronaut: Flyway VN__pt_br com história nomeada por app e destrutiva justificada; pool Hikari deliberadamente pequeno (o Postgres é compartilhado); CRUD via Micronaut Data + bulk via JDBC manual.
  • Gate Dart completo: templates/analysis_options.yaml canônico (novo rastreado, flutter_lints + regras de segurança assíncrona do piloto) e dart format --set-exit-if-changed . no gate Flutter/Dart (ci.yml, páginas, skills x-planejar/ x-implementar/meta-audit — a varredura de satélites do 0.17.34 pegou os 5 pontos).
  • Teste de regressão do valida-frontmatter: fixtures versionadas (scripts/fixtures-valida-frontmatter/, 10 casos) + testa-valida-frontmatter.py no CI e no pré-flight da release — era o script de maior blast radius sem cobertura; de quebra, frontmatter com YAML quebrado agora vira erro legível em vez de traceback.

  • Constituição 0.17.34 — dois pisos de token viram norma escrita (pedido do Gustavo): (a) §6 (Regras de IA): o CLAUDE.md, além de roteador, é carregado inteiro em toda sessão — backlog/histórico concluído migra para arquivo-acervo não carregado (padrão BACKLOG-HISTORICO.md; caso medido no central: −15k tokens/sessão); (b) §6: a saída do agente é tersa (estilo caveman) por default — telegráfica no chat, com carve-out explícito que agora inclui conteúdo de documentação (texto em docs/ sai em prosa normal pt-BR, §1.8) além da mensagem de commit, código, linha §6, tabelas e .ia/. Ecos: carve-out de engenharia/agentes.md ganha o item documentação; comentário do templates/claude-regras.md (rastreado, recarimbado) carrega os dois lembretes para os apps.

  • Constituição 0.17.33 — §6 enxuto em tokens: os dois bullets operacionais de rtk/caveman ("saída enxuta" e "disciplina de tokens") encolhem para o piso + ponteiro; o como (envelope rtk err nos gates, comando bare, exemplos de fechamento) já tinha dono em engenharia/agentes.md e engenharia/ferramentas.md (um fato, um dono, §1.9). Norma inalterada.

  • CLAUDE.md do central em dieta: o histórico do backlog (itens 0–52) migrou para BACKLOG-HISTORICO.md (acervo, não carregado pelo Claude Code) — o CLAUDE.md era ~20k tokens carregados em toda sessão, ~85% histórico; fica com regras + contexto + pendências + itens recentes (~7k). Ganha também: bloco TOKENS (gates via rtk err, comando bare), regra de migração contínua (>~10 itens → histórico) e a varredura de satélites no §8 (bump da constituição → conferir glossário/templates/publicar-docs/ app-novo/ia/READMEs — trata o candidato §6 da rodada anterior: o manifesto protege os artefatos copiados, as páginas do site só têm essa varredura).

  • Constituição 0.17.30: o pré-flight do /xadm-release deixa claro que worktree limpo com commits à frente do origin é o caso NORMAL — a IA não commita (REGRA Nº 2), então o conteúdo da sessão é commitado pelo usuário e o release apenas segue, sem auditar a autoria dos commits à frente. Evita o falso alarme de "commit que eu não fiz" no início do release. Tocado o template rastreado xadm-release-skill.md (+ cópia instalada).

Corrigido

  • Constituição 0.17.32 — rodada de reconciliação de drift (auditoria interna do central, 4 pareceres): (a) templates/xadm.css re-derivado da fonte do site — a cópia distribuída ainda carregava navy/burgundy, paleta que o logo real não tem (a vigente é azul royal #064490 + prata; comentários stale em templates/mkdocs.yml, mkdocs.yml e templates.md corrigidos juntos); (b) templates/docs.yml passo versions.json usava o placeholder <app> hardcoded em vez de "$SLUG" (contradizia a fonte única do slug e quebrava o 1º release versionado do app); (c) templates/anexos-readme.md prometia guarda extinta ("o CI bloqueia massa de dados") — agora diz a regra real (validador só bloqueia em docs/public/; fora de privado/ publica, responsabilidade do autor); (d) xadm-meta-audit-work realinhada ao pipeline atual — auditava a extinta /xadm-work (estágios *_phase, exigia mensagem de commit que o run concluído corretamente NÃO entrega desde a ordem implementar → documentar → commit); (e) instrução de instalação de skills unificada (app-novo diz 10 core incluindo xadm-setup; templates.md ganhou a linha/seção da /xadm-setup e aposentou os nomes pré-rename spec/refine/plan/work; ia.md §Como adotar delega ao manifesto em vez de mandar copiar só 2); (f) exemplos que ensinavam errado: app.json de publicar-docs.md sem aptabase_host (o contrato corrigido no 0.17.23), templates/app.json com Flutter 3.35.0 fora da baseline (gate do release barraria), templates/riscos.md com nomenclatura PROJ- legada, glossário 2 reorgs atrás (manual como nível 4, superado-por: sem aspas — formato que o validador rejeita) e estrutura legada (manual/, img/) em publicar-docs.md.

0.21.0 - 2026-07-04

Adicionado

  • Constituição 0.17.29: §6 (No CI/código) ganha o piso "o gate é fiel ao artefato que embarca"test roda no classpath, mas o que sobe é o fat jar/container; ordem, descoberta e configuração podem divergir (merge de META-INF, native-image, shading). O default é eliminar a divergência (determinismo/paridade), não "smoke em prod"; só onde a divergência é inevitável o gate exercita o artefato empacotado (sobe o jar/container e bate num endpoint). Detalhe do "como" em engenharia/ci-testes.md; regra concreta de stack (@ServerFilter honra @Order, @Filter legado não → ordem indefinida no fat jar) em engenharia/java-micronaut.md. Feedback §6 de app Micronaut.
  • Gate toolchain ∈ baseline da fábrica: a matriz-baseline.json passa a ser publicada em /toolchain/matriz-baseline.json; o pré-flight do /xadm-release bloqueia e o /xadm-docs 3b avisa cedo quando um app declara versão de stack (app.json/.fvmrc) não homologada na fábrica — pega o "manifest unknown" antes da tag, não mais só no 1º release (constituição 0.17.28, decisão 0003).

0.20.0 - 2026-07-04

Alterado

  • Constituição 0.17.24: o passo analytics do /xadm-setup pergunta o arquétipo do app (produto vs interno/admin) antes de sugerir eventos — produto mantém o baseline de product-analytics; interno/admin passa a mirar a ação sensível (quem fez), e não screen_view/retenção. Adicionado o caveat de que evento client-side é visibilidade operacional, não audit trail (auditoria de verdade pertence ao backend). Espelhado em central-de-apps.md.
  • Guia de IA (transversais/ia.md): seção opcional de otimização de custo de tokens — ferramentas de arquivo/busca em vez de despejo de shell, comunicação enxuta onde não custa clareza, e ferramentas pessoais opcionais que o agente pode oferecer (nunca impor).
  • Constituição 0.17.25: higiene de saída de comando — nova seção em engenharia/ci-testes.md (corte o verboso na fonte; reporter frugal sempre; nativas de arquivo sobre shell; proxy é complemento) + comando frugal por stack (flutter test -r failures-only, ./gradlew test --quiet --console=plain, …) nas páginas de stack, e a §6 afirma que o gate roda com reporter enxuto (verboso só sob falha).
  • Nova página engenharia/agentes.md (Trabalho com agentes de IA): consolida a disciplina de tokens do agente — input frugal (link p/ ci-testes) + output terso + carve-out verbatim (nunca comprimir: código, mensagem de commit, linha §6, tabelas de dado, .ia/). O estilo terso vira prática recomendada via hook SessionStart (caveman.sh, mesmo padrão do checa-constituicao; funciona sem plugin); passo no checklist de app novo. transversais/ia.md reconciliada. Sem bump (só doc/engenharia, não rastreadas).
  • Nova página engenharia/ferramentas.md (Ferramentas de token — rtk): o rtk (proxy que resume a saída de CLI antes do contexto) vira recomendação da casa — install/verify, habilitar (hook rtk hook claude), configurar como padrão (ignore_dirs por stack, tee em falha) e regras por stack (Gradle bare sem pipe + sdk default java p/ dispensar o prefixo JAVA_HOME= que fura o hook; git bare sem --porcelain; nativas sobre cat/find; rtk não cobre flutter). Reconcilia o conflito | tail da norma frugal (flags de reporter ficam; pós-processamento com pipe cede ao bare+rtk). ci-testes.md/agentes.md/ia.md reconciliadas. Sem bump (não rastreada).
  • engenharia/ferramentas.md passa a cobrir rtk (input) + caveman (output) como ferramentas recomendadas simétricas, cada uma com install/habilitar/configurar. Install real por plataforma dos repos oficiais (rtk-ai/rtk: brew/curl/cargo/Windows + rtk init -g; juliusbrussee/caveman: plugin do Claude Code / instalador universal). A receita do hook caveman.sh migrou de agentes.md (que ficou com o princípio + carve-out e aponta pra cá). Sem bump (não rastreada).
  • Constituição 0.17.26: auto-análise de uso das ferramentas de token no fechamento §6. A §6 e a skill /x-documentar ganham o passo (condicional a usar rtk/caveman): ao fechar, o agente mede (rtk gain/rtk discover; caveman = qualitativo), auto-corrige (bare/nativas/terso+carve-out) e roteia o gap sistêmico — recipe de stack → §6 (outros apps aprendem); comando verboso sem handler nativo → envolver com rtk err/rtk summary (ajuste de uso, resolve a maioria), RTK tracker só o residual. Nova seção "Auto-análise" em engenharia/agentes.md + hook opcional leve token-check.sh (eficiência do rtk gain no start); passo no app-novo.

0.19.5 - 2026-07-04

Alterado

  • Client_grade de analytics inclui aptabase_host (Aptabase self-hosted) (constituição 0.17.23; feedback §6). A key A-SH- self-hosted é inútil no cliente sem o host — o SDK Flutter exige InitOptions(host:) (≠ do DSN do GlitchTip, que já embute o host). Sem isso o /xadm-setup tinha que hardcodar/adivinhar o host e gravá-lo à mão no app.json (sujeito a clobber num re-provision). Agora o client_grade = aptabase_key + aptabase_host; central-de-apps + xadm-setup atualizados. Handoff auth: o AptabaseProvider devolve aptabase_host no client_config.

  • Metabase organiza por sub-pasta (grupo/cliente → app_id → dashboard + cards) (feedback §6 — o auth implementou, decisão 0014). Antes o central documentava dashboard+cards soltos numa collection (exigia sufixar os cards com app_id pra não colidir). Agora cada app ganha uma sub-pasta (collection filha, nome = app_id) dentro da collection do grupo/cliente, contendo o dashboard + os cards com nome canônico (sem sufixo, já isolados). Espelha o app.json. central-de-apps atualizado; andaime .ia/016-* apagado (feature pronta). Sem bump (docs page).

  • §6: fixture de API externa é CAPTURADA da instância real, não inventada (constituição 0.17.22; feedback §6). Um teste (ex. WireMock) verde sobre um shape fabricado é falso atestado — o mesmo "validador stale = falso 0 erros" que o §6 já combate, aplicado a fixtures de API (quebrou 2× em prod: Aptabase e Metabase, com app_key/id:-1 inventados). Agora a §6 (norma) e o x-documentar (§3 auditoria de lacuna) exigem: fixture de API externa capturada da instância real, e provider de API externa só marca "ligada" com ≥1 resposta real capturada.

  • /xadm-release: pré-flight roda o build de docs + CHANGELOG sem link relativo (constituição 0.17.21; feedback §6). (1) Referência no CHANGELOG = texto puro ou URL absoluta, nunca [texto](docs/…) relativo — o CHANGELOG é embutido em docs/ via snippet, o link vira docs/docs/… e quebra o --strict. (2) O pré-flight roda o BUILD de docs que o docs.yml roda (mkdocs build --strict com hooks + javadoc/dartdoc) — um gate de infra vermelho (dind) mascara os gates seguintes no CI, então rodá-los local evita descobrir em prod.

  • /xadm-docs: relevância por stack (evita falso-positivo do mudou_em stack-cego) (constituição 0.17.20; feedback §6). O mudou_em do manifesto é por-arquivo-global, não por-stack — uma mudança Java-only (ex. ci.yml Testcontainers) marca ci.yml defasado em app Flutter. Agora o /xadm-docs, para arquivo multi-stack customizado-por-app (o ci.yml, cujo diff verbatim é esperado), manda checar a entrada do CHANGELOG da versão mudou_em para ver se a mudança toca a stack do app — se não toca, não é defasagem pra ele (mantém a customização). Decisão: guidance, não campo stacks: no manifesto — o ci.yml é multi-stack, e um stacks: [java] esconderia updates Flutter-relevantes (nav-check etc.).

Corrigido

  • ci.yml Testcontainers: DOCKER_HOST via runner, não docker.sock (topologia dind isolado) (constituição 0.17.19; feedback §6 — corrige o v0.19.4). O DooD por docker.sock que saiu no v0.19.4 não funciona no runner da org (act_runner com dind privilegiado → o mount do socket do host vira "not a valid volume"), e todo @Testcontainers falha no CI. Fix org-wide mantendo o isolamento: o config.yaml do act_runner injeta DOCKER_HOST=tcp://172.17.0.1:2375 (gateway do dind) + TESTCONTAINERS_HOST_OVERRIDE + RYUK_DISABLED nos jobs → o templates/ci.yml fica agnóstico (removido o docker.sock). Detalhe/config em forgejo.md. Pendência do Gustavo: configurar o act_runner.

0.19.4 - 2026-07-03

Alterado

  • Definição de pronto (§6): deferir teste é custo × valor, não racionalização (constituição 0.17.18; feedback §6). "Exercitado end-to-end" e "baixo risco" são justo as frases que deixam a guarda de regressão barata escapar — sobretudo em segurança/privacidade/contrato. Agora a §6 (norma) e as skills x-implementar/x-documentar exigem, por lacuna de teste, uma classificação explícita custo × valor: default = escrever a guarda barata e proporcional agora; só deferir no quadrante caro E de baixo valor; comportamento sensível → escrever a guarda agora. Bump 0.17.17→0.17.18 (as duas skills rastreadas + §6).

  • Fluxo do pipeline: /x-implementar → /x-documentar → commit (constituição 0.17.17). O /x-implementar, ao concluir o plano, deixa de entregar a mensagem de commit — aponta pro /x-documentar, que faz a revisão geral (avalia lacuna de doc e de teste, §6), destila o durável pra docs/, apaga o andaime (.ia/NNN-*) e entrega a mensagem de commit do ciclo. Antes o commit era sugerido no x-implementar; agora o ciclo fecha no x-documentar. Bump 0.17.16→0.17.17 (as duas skills rastreadas + ia.md).

  • Feedback §6 (docs de engenharia/central): paleta por grupo, receita de screenshots, gotchas, formas de provider — sem bump (engenharia/documentacao não são rastreadas). (1) A paleta do cliente passa a ser gatilhada pelo grupo: cliente do app.json (marca derivada do logo do cliente), não mais o "veste a marca declarado" do #31 — mais simples (engenharia/flutter). (2) screenshots-manual ganha o seed com DDL do schema PowerSync + o gotcha registerSingletonAsync. (3) gotcha do ink_sparkle.frag em bump de SDK (flutter clean+pub get) em engenharia/flutter. (4) central-de-apps destila as três formas de provider (find-before-create / forjar-token / reuso-persistido) e java-micronaut ganha 2 armadilhas REST (PUT substitui coleção → read-modify-write; nomear por escopo em container compartilhado).

  • Check de nav-drift (checa-nav.py) no gate de código (constituição 0.17.16; feedback §6). Num repo stack+MkDocs o gate de código não roda mkdocs → um .md novo fora do nav: só estoura no docs.yml (que não roda a cada PR de código) e órfãos acumulam (o app relatou 3 decisões + 1 runbook órfãos por 2 fases). Novo scripts/checa-nav.py (stdlib): FALHA se um .md de docs/ não está no nav: nem excluído (isenta README.md de pasta); rodado ativo no ci.yml (tolerante sem docs/), publicado como os outros validadores. §6 esclarecida: "doc do estado atual" inclui aparecer no índice, não só existir. Dogfood: pegou o decisoes/0006 órfão no próprio central (corrigido no nav).

  • Constituição §2: provider automagico não precisa de runbook de "como usar" (constituição 0.17.15; feedback §6). O que roda sozinho (ex. provider build-time da Central de Apps — "como usar" = a skill, "porquê" = a decisão) não ganha runbook; sobra config-de-operador (envs + como obter) + diagnóstico, numa seção "Operar" da própria decisão, não num runbook que duplica o design. Os runbooks provedor-*.md (no auth) morrem — cleanup do auth (handoff).

  • Auto-config do Metabase no /xadm-setup — fatia do central (constituição 0.17.14; feature 016, desenhada via /x-desenhar/x-definir/x-refinar/x-planejar/x-implementar). Depois do Aptabase, o broker auto-configura o Metabase (API real): collection(cliente) → dashboard(app) → cards baseline que adaptam aos eventos escolhidos; idempotência por id estável; resposta honesta com sub-estados aptabase+metabase; 6 queries ClickHouse = template canônico no broker; grava metabase_dashboard_id (pro embed futuro). central-de-apps (provider analytics) + xadm-setup-skill (passo). A implementação do broker Metabase é do repo auth (handoff).

  • Rota de diagnóstico /test no baseline de observabilidade (opt-in) (constituição 0.17.13; feedback §6). Verificar pós-deploy que o erro chega no GlitchTip era improvisado por app; agora engenharia/flutter (tela oculta login-gated com botão "enviar exceção de teste") e engenharia/java-micronaut (endpoint autenticado /test/glitchtip) trazem a receita, e o /xadm-setup oferece scaffoldar (opt-in, com o OK do dev) junto da instrumentação. Não obrigatório (backend/cron não é forçado a ter UI de diagnóstico).

  • Aptabase no /xadm-setup: provisão full-auto forjando o token (sem API) (constituição 0.17.12, mecanismo corrigido em 0.17.15; feedback §6 de um app). O Aptabase self-hosted não tem API e autentica por sessão. Descoberto empiricamente (decisão 0013 do auth): o token é um JWT simétrico (HS256) assinado com o secret do próprio tool → o broker forja o token (secret no env do auth) e abre sessão direto, depois cria o app → A-SH-…. (O "magic-link dos logs do Coolify" não funciona — o Coolify não expõe logs de service.) É o padrão "provider sem API → forjar o token"; guardas: fail-fast, versão fixada, secret forja sessão de qualquer usuário. O central-de-apps documenta o fluxo + o padrão; o passo do /xadm-setup passa a perguntar ao dev quais eventos registrar e scaffolda o helper só para os escolhidos.

  • Ponte app.json--dart-define no build Flutter-web + /xadm-setup honesto (constituição 0.17.11; feedback §6 de um app Flutter-web da Central de Apps). O /xadm-setup passo 5 assumia que "o Dockerfile/CI já lê o app.json", mas o scaffold hardcodava ARGs e nem tinha jq. engenharia/flutter ganha a receita concreta (instalar jq + flutter build … --dart-define= $(jq -r .features.<x>.<ref> docs/app.json)) e reconcilia "config no repo" (= app.json + ponte, não hardcode; client-grade não precisa de build-arg do Coolify — só segredo). O passo 5 passa a mandar garantir/criar a ponte (aponta pra receita), não "confira que já existe".

  • Identidade visual: app que veste a marca do cliente usa a marca do cliente, não a da casa (feedback §6 do bi-comercial/OnPetro). A engenharia/flutter tratava "paleta = a da casa" como absoluto; agora a identidade da casa é o default (app da X-Adm / app de cliente sem marca própria) e um app exclusivo que veste a marca do cliente usa a paleta/logo/tipografia do cliente (declarado no app.json). O gatilho é vestir a marca do cliente, não o mero cliente:; o mecanismo da casa (tema por ColorScheme, app-icon, feature-first) segue valendo em todo app. Sem bump (engenharia é regra viva, não rastreada).

0.19.3 - 2026-07-03

Corrigido

  • checa-dogfood.py reconhece skills em diretório (destrava o deploy do v0.19.2). O gate de CI comparava .claude/skills/<nome>/SKILL.md só com templates/<nome>-skill.md (plano) e acusava as 6 x-* (modelo diretório) como "sem template canônico" → job validar vermelho → deploy travado. Agora compara o diretório inteiro (SKILL.md + references/) para as x-* e mantém o modelo plano para as xadm-*.

Alterado

  • Pré-flight do /xadm-release roda todos os checks do CI (constituição 0.17.10; feedback §6 do incidente acima). O gate local rodava só lint-mermaid + gera-manifesto --check + valida-frontmatter, mas o CI roda também checa-dogfood.py e checa-export-download.py — por isso o drift passou no pré-flight e só estourou no CI depois da tag pushada. O §1 agora manda rodar todos os checks do CI do repo (condicional "se o repo os tiver", pois são central-only).

0.19.2 - 2026-07-03

Adicionado

  • Recipe GlitchTip/Sentry para Micronaut e armadilha @Consumes em endpoint de <form> na página engenharia/java-micronaut.md (feedback §6 do auth). Sentry via io.sentry:sentry + sentry-logback (SentryAppender no logback.xml, minimumEventLevel=ERROR, DSN vazio → no-op, zero código no negócio; espelha o bloco Flutter). @Consumes: @Post assume JSON → 415 em form x-www-form-urlencoded; armadilha de teste (o HttpClient manda JSON por default).

Alterado

  • Contrato do /provision (Central de Apps): injetar APLICA a config (reinicia), não só grava (constituição 0.17.9; feedback §6 do auth). Env upsertado não recarrega em processo vivo → o broker reinicia o recurso Coolify ao injetar, e injected:true passa a significar "injetado E em vigor"; reinicia só quando o valor mudou (lê o atual + compara), pra não derrubar serviço sensível (auth) à toa em re-run. Provado no auth (decisão 0011).

  • templates/ci.yml Java dá Docker ao Testcontainers (DooD) (constituição 0.17.9; feedback §6 do auth). O job container: ci-java não montava o socket do host → todo @Testcontainers (padrão da casa p/ "banco real") falhava no CI com "could not find a valid Docker environment", deixando o gate §6 "No CI (código)" vermelho crônico. Correção: container.volumes monta /var/run/docker.sock; pré-requisito do runner (act_runner valid_volumes) documentado em infraestrutura/forgejo.md. TESTCONTAINERS_RYUK_DISABLED=true já vinha no ambiente, mas não bastava — faltava o socket.

  • Skills de workflow renomeadas e realinhadas ao ACT 1.0 (constituição 0.17.8). O pipeline spec → refine → plan → work → compound virou x-desenhar → x-definir → x-refinar → x-planejar → x-implementar → x-documentar, adotando o split entrevista/spec do ACT 1.0 (x-desenhar conduz a entrevista e grava o prompt .ia/NNN-*-prompt.md com o rastro L# embutido; x-definir escreve a spec referenciando os L#), tarefa = corpo de Work Item embarcado no plano, e especialização de stack via references/<stack>.md (Flutter portado do ACT + Micronaut autorado) carregada pelo §0 — sem variantes-skill. Preserva os invariantes da casa (NÃO commita, §0, gate da stack, §6, ghost mode, lineage .ia/, storage .ia/ sem .act/). Cada skill agora é um diretório templates/<nome>/ (SKILL.md + references/). Manifesto, gera-manifesto.py, xadm-docs e as referências (CLAUDE.md, ia.md, constituição, app-novo, templates.md, engenharia) atualizados. Apps migram oportunisticamente via /xadm-docs. Ver docs/decisoes/0006-skills-workflow-act1.md.

  • Constituição 0.17.7 — "idempotente" = procura-antes-de-cria (feedback §6: dois projetos com o mesmo nome no GlitchTip). O contrato dizia só a palavra "idempotente", que a implementação leu como cria-depois-procura — e como o GlitchTip permite nome duplicado, um re-run (ou falha no find + nova chamada) duplicou o projeto. central de apps §Provedores agora define o mecanismo: o provider checa se o recurso já existe (por nome/app_id) e reusa, nunca cria às cegas; onde o provedor permite nome duplicado, o find é obrigatório. O guard find-before-create em si é Camada 2 (auth — o 377c050 corrigiu o find). Bump PATCH 0.17.6→0.17.7.

  • Constituição 0.17.6 — /provision responde estado real + /xadm-setup instrumenta o código (feedback §6 da implementação do auth). Três furos: o /provision respondia 200 com enabled:true sem dsn quando o provider falhava (indistinguível de sucesso); a injeção no Coolify falhava em silêncio (best-effort, só WARN — token 401, DSN não injetado, ninguém soube); e o setup ligava a integração sem instrumentar o código. Correções em central de apps: a resposta do /provision carrega o estado real por provider — provisão (state/last_error) e injeção (injected + motivo), com não-2xx se nada ligou; o /xadm-setup confere e não grava enabled sem o ref, avisa em injected:false (setar o env à mão) e não re-chama provision "pra confirmar" (isso gerava projeto GlitchTip duplicado). E a skill passa a instrumentar o código (scaffold + guia, com OK do dev): instalar o SDK, envolver o runApp (SentryFlutter.init), guiar os pontos de captura — recipe em engenharia/flutter. O guard find-before-create do provider é Camada 2 (auth). Bump PATCH 0.17.5→0.17.6.
  • Constituição 0.17.5 — convenção: projeto GlitchTip nomeado pelo app_id (feedback §6 da implementação do auth). O slug do projeto GlitchTip é sempre slugify(nome) (o slug do corpo é ignorado, imutável por PUT) e o dsn usa o id numérico, não o slug. Convenção registrada na skill xadm-setup (passo glitchtip) e em central de apps §Provedores: o broker nomeia o projeto pelo app_id (slug estável e curto), decorrência do app_id canônico. A trivia da API do GlitchTip (slug ignorado no corpo, PUT, DSN por id) fica no GlitchTipProvider do auth (Camada 2), não no contrato central. Bump PATCH 0.17.4→0.17.5.
  • Identidade visual reconciliada com o logo + norma visual pra apps Flutter (feedback §6). O xadm.css afirmava paleta "extraída do logo", mas o xadm-logo.png é azul royal + prata, sem o burgundy #8b3a3a documentado (verificado amostrando o PNG). Decisão do Gustavo: derivar do logo real — a paleta da casa passa a ser azul royal #064490 (primária) + médio #2a5b97 (accent) / claro #7092bb / escuro #042c5e + prata #939495 (neutro); sai o navy/burgundy. docs/stylesheets/xadm.css vira a fonte-da-verdade dos tokens (docs e apps consomem), e engenharia/flutter ganha a seção Identidade visual (paleta→ColorScheme, logo + receita de app-icon flutter_launcher_icons, tipografia/densidade como decisão). O ThemeData compartilhado, o kit mínimo de componentes e a variação quadrada do logo ficam para uma spec do padrão de identidade visual de apps (barato agora, resto na spec). Sem bump da constituição (docs/assets, não artefato rastreado).
  • Constituição 0.17.4 — broker de setup autentica por token de serviço (M2M) (feedback §6 da implementação do auth). O contrato pressupunha login humano (JWT xadm admin/Firebase) pra chamar o /api/setup/** — mas é endpoint máquina-a-máquina (o /xadm-setup), e nenhum CLI tem como obter esse JWT (loopback-OAuth inexistente). Agrava que o /provision recebe production_url e injeta env no recurso Coolify → num endpoint aberto, a auth importa de verdade. Nova norma (§7 + central de apps seção "Auth do broker de setup" + xadm-setup-skill): token de serviço, com força casada à exposição (interno/VPN → simples; público → segredo forte ou rotativo por HMAC-de-data, nunca fórmula pública); a regra de geração vive fora de banda (servidor + admins), jamais na skill ou em doc publicada — a skill conhece só o formato e pede o valor. Registra o gap "como obter a credencial de setup". Bump PATCH 0.17.3→0.17.4; manifesto regenerado (xadm-setup-skill).
  • Constituição 0.17.3 — Central de Apps: injeção de config (não só secret) e web ≠ server (feedback §6 da implementação do auth). A tabela "duas naturezas" juntava web/server e dizia que o client-grade vai como build-arg — só vale pra web (bundle). Um app server lê config do env em runtime, então o client-grade dele (ex. SENTRY_DSN) também é env injetada no Coolify, não build-arg. Correções em central de apps: linguagem "injeção de secret" → "injeção de config" (client-grade + secret); tabela com colunas web / server / mobile; checkpoint de deploy garante a config (não só secret); ponteiro pro endpoint de env do Coolify. Bump PATCH 0.17.2→0.17.3. (Mantido o modelo de 3 checkpoints — não adotada a opção de dobrar a injeção no /provision.)

0.19.1 - 2026-07-01

Corrigido

  • Diagrama Mermaid da Central de Apps + lint no gate local. O sequenceDiagram de central-de-apps.md tinha um ; numa mensagem (separador de statement no Mermaid) que quebrava o lint-mermaid do CI e travava o deploy desde o push do build-time — sem aparecer em nenhum check local, porque mkdocs build --strict não parseia diagramas. Corrigido o ;; e o lint de Mermaid entra no gate local (constituição 0.17.2): /xadm-work e /xadm-plan (verify docs), pré-flight do /xadm-release (bloqueia antes de taggar) e o gate docs documentado em ci-testes. Bump PATCH 0.17.1→0.17.2; manifesto regenerado (skills work/plan/release).

0.19.0 - 2026-07-01

Adicionado

  • Constituição 0.17.0 — Central de Apps (Camada 1, paradigma BUILD-TIME). Nova ## 7 + central de apps: a integração de um app com a infra X-Adm (erros/GlitchTip, arquivos/Garage, analytics Aptabase+Metabase, docs) é configurada em build-time, não amarrada em runtime. O app declara no app.json (features vira objeto por funcionalidade); a skill nova /xadm-setup (entre codar e /xadm-release) pergunta o que ativar, provisiona via o auth-broker (que tem os tokens admin) e grava o resultado client-grade no app.json — o build embarca, sem buscar config no boot. Runtime só o mínimo: corretores (embed Metabase/presign Garage) e feature flags (protocolo próprio — spec 014). auth = broker + configurador de secrets (Coolify/CI) + corretor; central.xadm.biz = dashboard (mostra o configurado + links, aprova acesso de terceiros). 3 checkpoints (setup → guard soft na /xadm-release → guard de deploy no ci.yml); 2 naturezas × plataforma (client-grade web=build-arg / mobile=--dart-define; secret web=Coolify / mobile=org-CI); fronteira de dados (auth×app; cliente_id claim×FK). Tocados: templates/app.json (features objeto), valida-frontmatter.py (rejeita chave desconhecida), skill xadm-setup nova, guard soft na xadm-release, placeholder de deploy no ci.yml, ecos em publicar-docs/app-novo/flutter; Bugsink→GlitchTip reconciliado (grep=0). Bump MINOR 0.16.1→0.17.0. Substitui o desenho runtime anterior (não shipado). Camada 2 (código auth/central/apps) + feature flags (014) em specs próprias.

Alterado

  • Constituição 0.17.1 — corretor autoriza por app + provisão por app_id (achados do plano de implementação da Camada 2 no auth). O contrato do corretor exigia só JWT válido (autenticação); agora a §7 e central de apps exigem autorização por app — o claim do JWT casa com o app do recurso (403 cross-app): usuário logado no app A não cunha embed/presign de recurso do app B. E a §Catálogo separa provisão (por app_id) de acesso (por (cliente, app), derivado dos oauth_access_grants) — não há tabela de pares para a provisão. Bump PATCH 0.17.0→0.17.1 (só docs de padrão; nenhum artefato rastreado mudou).
  • Constituição 0.16.1 — migração de conteúdo cross-repo + template×piloto (feedback §6 do authui). A regra de migração só cobria conteúdo do próprio repo (guias/ por conteúdo); agora a §3 e a /xadm-docs dizem que doc/runbook que pertence a outro repo, achado neste, é realocado para o repo dono — não absorvido/relabelado no operacao/ local. E o app-novo.md esclarece template × piloto: o template (sincronizado via manifesto) é a única fonte de cópia; o app piloto/de referência é exemplo provado/destilado (Engenharia), nunca base de cópia. Bump PATCH 0.16.0→0.16.1; manifesto regenerado.
  • Constituição 0.15.3 — /xadm-refine-spec com passada de contexto profunda. O refine da casa confirmava que os artefatos existiam, não que os fatos afirmados sobre eles eram verdadeiros — então não pegou o que o refine nativo do ACT pegou (ex.: app.json real sem slug, app_id divergente, conflito de audiência do authui). Correções no template e na cópia instalada: §1 vira passada profunda (ler o conteúdo de cada referência; conferir cada fato contra o artefato real; mapear tabelas/endpoints/identidade/namespaces; rastrear uma instância real ponta a ponta; e, se paralelizada, fazer isso UMA vez antes das dimensões); dimensão 2 cobra "fato conferido LENDO o artefato"; e uma lente transversal do implementador ("se eu fosse construir isto agora, onde travaria?"). Bump PATCH 0.15.2→0.15.3 (artefato rastreado mudou); manifesto regenerado.
  • Doc de infra — endpoint de env/secret da API do Coolify. O coolify.md passa a documentar o PATCH /api/v1/applications/{uuid}/envs/bulk (upsert em lote, Bearer; "Secret" = env marcada como Secret, não um tipo à parte; flags Build/Runtime) que o guard de deploy da Central de Apps usa para injetar os secrets de build — tira a Fase 4 do broker no auth do "spike do zero" (fato verificado na doc oficial do Coolify).

0.18.3 - 2026-06-30

Corrigido

  • Constituição 0.15.2 — desambiguação versão-do-site × versão-da-constituição. Um app em bootstrap (sem /xadm-docs instalada, só com o link da constituição) ficou em dúvida entre 0.15.1 (constituição) e 0.18.2 (site): o número do site aparece nu e gritante (VERSION, /versao.txt, tag vX.Y.Z, CHANGELOG, e mais ainda num clone local do repo central), enquanto o da constituição é discreto. Correções: a §6 da constituição passa a explicitar "duas versões, não confundir" (com a armadilha do clone local e do bootstrap); nova seção Duas versões: site x constituição em engenharia/versionamento.md; guard na skill /xadm-docs (a vigente vem só de constituicao-versao.txt, nunca de VERSION/tag); nota roteadora no CLAUDE.md do central; e correção do path stale docs/padroes/constituicao.md na skill /xadm-release.
  • /versao.txt auto-rotulado (site X.Y.Z). O Dockerfile passa a gravar o número do site rotulado em vez de nu, para não ser confundido com a versão da constituição.
  • Nota da distinção também no checklist de app novo (app-novo.md §3): o que o app rastreia é só constituicao-versao.txt; VERSION//versao.txt/tag são do site.
  • templates/mkdocs.yml — ordem dos plugins corrigida. O print-site estava antes do swagger-ui-tag, contrariando o próprio comentário ("DEVE ser o último") e quebrando o mkdocs build --strict (achado na adoção real). Reordenado para print-site por último.
  • Bootstrap sub-instalava as skills. O checklist de app novo (app-novo.md) listava só xadm-docs e xadm-release, e o manifesto.json não distinguia skill core de opcional — quem fazia bootstrap pela leitura instalava 2 de 8 (caso real). Correções: o manifesto.json ganha o campo opcionais (hoje só xadm-docx; gera-manifesto.py emite e o --check guarda); o app-novo.md passa a mandar instalar todas as *-skill.md do manifesto exceto as opcionais, listando as 8 core e apontando o manifesto como a lista mecânica completa; a /xadm-docs pula as opcionais na conferência de defasagem (opcional não-instalado não é defasagem).

0.18.2 - 2026-06-26

Adicionado

  • Navegação Anterior/Próximo no rodapé das páginas (navigation.footer). Habilitada a feature nativa do MkDocs Material no site central e no templates/mkdocs.yml dos apps: cada página ganha links "Anterior" (esquerda) / "Próximo" (direita) derivados da ordem do nav:, servindo o modo "ler como livro" (§1.7) — mais útil ainda no manual e no livro do projeto dos apps. Bump PATCH 0.15.0→0.15.1 (artefato rastreado mudou); apps re-baixam o template via /xadm-docs na migração oportunista.

Alterado

  • Constituição 0.15.0 — screenshot do manual entra na definição de pronto (§6). A metade (2) "doc do estado atual" agora lista o screenshot do manual entre os "estados atuais que mentem": mudou UI retratada numa imagem (botão novo, rótulo, layout) → regenerar o PNG afetado é parte do pronto, e a verificação inclui abrir a imagem e confirmar o elemento novo, não só rodar o gerador (gerador que roda sem semear o estado certo "passa" mostrando a tela velha — a mesma falha da metade (1)). O runbook Screenshots do manual ganhou a seção "Revisar o diff antes de commitar" com a armadilha do diff de só-ruído (marca d'água/elemento aleatório → reverter os PNGs de só-ruído, manter o que teve mudança visual real). Loop §6 de um app de BI Flutter (vantroba-bi v1.5.0: botão de export novo, texto atualizado, .png ficou na tela velha — pego só depois).

Adicionado

  • Engenharia/Flutter: padrão de export XLSX sem lib licenciada. Registrado na página de Flutter: usar o excel (justkawal, MIT) + pós-processar o OOXML com archive para freeze pane/autoFilter/outline (que o excel 4.0.6 não faz — verificado no fonte), em vez de trocar por Syncfusion (licenciado); com as armadilhas (Archive imutável, download Web manual, edição idempotente + smoke real) e a nota de hierarquia × sort. Imagem/logo no XLSX ficou fora de escopo (sem receita de injeção). Loop §6 de um app de BI Flutter.

Corrigido

  • Menu de abas: o vão Teoria/Prática sumia na própria página Aplicações. A regra que empurra o grupo da direita (Aplicações · API Reference · Mudanças) mirava pelo href ([href*="aplicacoes"]), mas o Material reescreve o link da aba ativa para ./ — que não contém "aplicacoes" — então, ao abrir Aplicações, o margin-left:auto não casava e todas as abas agrupavam à esquerda. Passou a mirar por posição (nth-last-child(3) = início do grupo da direita), imune ao estado ativo. Regra é exclusiva do xadm.css do portal central; apps não usam.

  • Release: pré-flight pedia autorização (constituição 0.14.34): o .claude/settings.json central não tinha git status/git log no allow-list (o template da skill já os prescrevia — estavam dessincronizados), e o pré-flight foi rodado num bloco multi-linha com git --no-pager … (duas coisas que o matcher recusa: comando composto não casa com um padrão, e a flag antes do subcomando quebra o git status *). Allow-list ganhou git status/git log/git diff; a skill (template + cópia) deixa explícito: um comando por chamada Bash (sem bloco multi-linha) e git puro sem --no-pager (4º veneno).

0.18.1 - 2026-06-26

Adicionado

  • slug no app.json — fonte única do identificador do app (constituição 0.14.32): o slug (pasta no bucket docs-sites/, path do site_url, nome do .docx) vivia duplicado em mkdocs.yml, docs.yml, CLAUDE.md e na skill de release, mas não no app.json, seu lar natural. Agora o template do app.json tem slug (kebab-case, "para sempre"); o docs.yml deriva dele o target do rclone e o site_url (em vez de hardcodar <app>); o export_docx usa-o no nome do .docx (fallback p/ o diretório-raiz); e o valida-frontmatter confere que o site_url do mkdocs.yml bate com o slug (igual ao cross-check de cliente:). Opcional p/ app legado (migração oportunista).
  • Gate de CI da lista de download da /xadm-docx (scripts/checa-export-download.py): confere que a lista hardcoded de arquivos baixados (skill + página) bate com o pipeline publicado (scripts/export-docx/ + reference/logo). Fecha o loop §6 do admonitions.py que defasou a lista.

Alterado

  • Export .docx: nome de entrega auto-descritivo (constituição 0.14.31): sem 2º argumento, o export_docx.py gera <slug>-<nível>[-v<versão>].docx na raiz do repo (antes: projeto.docx/pre-projeto.docx genérico, que colidia entre apps/releases na entrega). slug = nome do diretório-raiz; nível = pre-projeto|projeto (pelo caminho); versão = git describe --tagsVERSION → omitida; fallback genérico se não derivar. A skill /xadm-docx e a página passam a usar o default; o .gitignore do app (e o gitignore-flutter) ganha /*.docx (root-anchored — não pega um pré-projeto .docx commitado, §1.3). Correção junto: o download fresco da skill não baixava o admonitions.py (passo do pipeline desde 0.14.26) — incluído na lista.

  • Site central: ordem das abas, home e layout da Aplicações. Abas do topo reordenadas (Mudanças foi para o fim: Início · Documentação · Engenharia · Transversais · Aplicações · API Reference · Mudanças); a home ganhou um item explicando Transversais (IA, infraestrutura, glossário) com link; e as páginas Aplicações e API Reference (conteúdo montado via JS, sem headings no markdown → TOC vazio) receberam hide: toc, colapsando a coluna direita vazia que deixava o layout "agrupado". Só apresentação do site central; nada de artefato rastreado.

Corrigido

  • App publicado só em dev/ aparecia em "Outros (sem app.json)" (constituição 0.14.33): no layout versionado (decisão 0004), o central lê a app.json da raiz do bucket (docs-sites/<slug>/app.json), mas o docs.yml só a sincronizava em <slug>/dev/ — e o passo que mexe na raiz é release-only (publica-versao.py nem toca na app.json). Logo, app que só deu push em master nunca categorizava (caía em "Outros"). O docs.yml agora faz rclone copyto site/app.json …/<slug>/app.json (aditivo) em todo push. Caso real: thoms-integracao-produto-ecom.

  • Release sem prompt — inspeção de arquivo pela ferramenta Read, não por shell (constituição 0.14.30): a skill /xadm-release mandava ler o CHANGELOG.md mas não dizia como, e uma inspeção com pipe (sed … | grep, rtk grep … | head) disparou o único prompt de um release (pipe é recusado por princípio, fora do allow-list). A skill (template + cópia deste repo) agora manda inspecionar VERSION/CHANGELOG/diff pela ferramenta Read (ou git diff), nunca por sed/grep/cat/rtk grep/| head — 3º veneno documentado. O Read não precisa de allow-list nem confirma.

0.18.0 - 2026-06-26

Adicionado

  • Gate de dogfood das skills no CI (scripts/checa-dogfood.py): somos a vitrine, então as skills instaladas (.claude/skills/<nome>/SKILL.md) têm de bater com o template canônico (templates/<nome>-skill.md). O CI falha em drift — descoberto via loop §6: o próprio repo rodava /xadm-spec//xadm-refine-spec//xadm-plan defasados (sem NNN/segredo/lib-capability) porque as cópias nunca eram re-derivadas. As 3 cópias defasadas foram sincronizadas. xadm-release é adaptada por repo e fica de fora do gate.

Alterado

  • Spec/refine: verificar capacidade de lib de terceiro na FONTE antes de especificar (constituição 0.14.27): a /xadm-spec (§1) passa a mandar confirmar, na fonte/changelog da versão em uso, que um recurso de lib/SDK externo do qual a feature depende existe — com o pesquisador de docs da stack (ex. act-flutter-docs-researcher) — antes de especificar; especificar API inexistente é inventar capacidade (§1.2). A dim. 2 (Premissas) da /xadm-refine-spec reforça: recurso de lib assumido sem conferir no fonte = achado crítico. Origem: loop §6 do BI Transporte (feature de export xlsx — o researcher confirmou no fonte da lib 4.0.6 que não havia API de imagem/outline, evitando retrabalho).

  • Export .docx: fim do auto-anexo de .md irmãos (constituição 0.14.28): o export_docx.py deixava de fora o que era embutido, mas anexava ao fim todo .md irmão não-embutido — slurpando páginas que o livro só linka/resume (ex. etapas de projeto/), gerando conteúdo duplicado e um anexo solto após as Decisões. Agora o .docx é o index + só o que ele embute via --8<-- (igual ao site: link não entra, o link já é a relação). Pré-projeto passa a embutir seus anexos no fim do index.md (cada # ainda ganha quebra de página). Avisado na página Exportar para .docx.

  • Export .docx: links para fora do Word viram texto (constituição 0.14.29): o livro linka legitimamente para ADRs (docs/decisoes/*.md) e outras páginas de nav — funcionam no site, mas no .docx (só o livro) virariam hyperlinks mortos (apontam para um .md inexistente). Um filtro lua (frontmatter.lua) remove o href de links relativos (alvo fora do .docx), mantendo o texto; URL absoluta e âncora interna seguem clicáveis, e imagens (Mermaid) não são tocadas. Guidance na página: cross-ref de conteúdo só-no-site se cita por nome/número, não por link. Docx-only — no site os links funcionam.

0.17.1 - 2026-06-26

Adicionado

  • Export .docx: admonitions viram callout (constituição 0.14.26): !!! tipo "Título" / ??? tipo (que o pandoc não entende e despejava literal no Word) agora passam por um pré-processador (admonitions.py, antes do pandoc) que os converte em blockquote com título em negrito → estilo Block Text (callout) do xadm-reference.docx, com o tipo como rótulo pt-BR (Nota/Aviso/Dica/…). O autor mantém o !!! na fonte (box nativo no site); só o .docx é adaptado. Docx-only — o site já renderiza admonitions.

  • Export .docx: legenda por diagrama + estilo de código + Título 4–6 (constituição 0.14.25): (a) render_mermaid%% caption: <texto> no bloco e emite a legenda na figura do .docx; (b) o xadm-reference.docx e o make_reference.py ganharam SourceCode/VerbatimChar (monoespaçada, fundo e borda leves) — antes ```json/código inline saíam na fonte do corpo — e Título 4–6 na identidade X-Adm (Verdana azul, decrescente), para o conteúdo que chega a H4+. (c) Documentada a convenção de que fragmento --8<-- se autora no nível do embed (modelagem.md em ###, não #) — nada rebaixa heading, no site nem no .docx (constituição §5). Só docx/reference; o site já estilizava código e todos os níveis via Material+CSS.

Corrigido

  • Export .docx: diagnóstico de Mermaid quando falta o Chrome (constituição 0.14.24): com mmdc instalado mas sem Chrome (de sistema ou do puppeteer — caso típico de CI/runner limpo), o erro dizia "mmdc ausente — instale o mmdc", mandando pro lado errado. Agora distingue "mmdc ausente" de "mmdc presente, Chrome falhou" e aponta as saídas offline (instalar chromium · PUPPETEER_EXECUTABLE_PATH · npx puppeteer browsers install chrome-headless-shell), sem empurrar pro .ink. Nota de troubleshooting na página Exportar para .docx. (A detecção automática de Chrome do sistema + --no-sandbox já existia na v0.17.0.)

0.17.0 - 2026-06-26

Adicionado

  • Pipeline de exportação para .docx no padrão X-Adm (constituição 0.14.23): centraliza na toolchain o pipeline Markdown→Word (pandoc + reference-doc + Mermaid→PNG), derivado e saneado da PoC poc-pied. Python-only cross-platform (Linux/Windows/macOS) + o filtro nativo do pandoc (frontmatter.lua); reference client-neutral, Mermaid offline por default (mmdc; .ink só opt-in com aviso de confidencialidade, §1.9), pré-processador de --8<-- (o pandoc não expande snippets). Distribuído como os validadores: scripts em scripts/export-docx/ rastreados no manifesto.json e publicados em /toolchain/raw/scripts/export-docx/; o reference+logo publicados crus (binários, fora do manifesto). Inclui a skill /xadm-docx (baixa o pipeline fresco e gera o Word, sem commitar), a página Exportar para .docx e o §1.3 acionável — distinguindo asset de tooling (versionado: css, reference.docx, logo) de documento gerado (não commitado: o .docx, o site).

  • Segredo nunca entra no Git — nem no andaime .ia/ (constituição 0.14.22, §1.9): o .ia/ é versionado e o -prompt.md (cola crua do pedido) é onde uma credencial real vaza por descuido — aconteceu. Regra nova: nenhum arquivo do repo (.ia/, docs/, config) carrega segredo real; usar placeholder (<TOKEN>, ${VAR}) + ponteiro pro valor real (secret da org no Forgejo, env, cofre); se vazou pro histórico, rotacionar (apagar o arquivo não basta — o Git guarda; mesma resposta dada ao vazamento das keys DOCS_S3). .ia/ segue versionado (a trilha do andaime é o objetivo — não se gitignora). Eco no fluxo de IA e nas skills /xadm-spec e /xadm-plan.

Corrigido

  • .ia/NNN-*NNN é o id da linhagem, não sequência global de arquivos (constituição 0.14.21): as skills /xadm-spec e /xadm-plan nomeavam .ia/NNN-titulo-spec.md / NNN-titulo-plan.md sem dizer o significado de NNN, e o agente tratava como sequência global de arquivos, ainda inventando um slug novo por estágio (ex. errado: 001-definicao-prompt002-integracao-...-spec), quebrando a rastreabilidade. Os dois templates passam a especificar que NNN identifica a linhagem (a feature): prompt, spec e plan da mesma linha compartilham NNN e slug, mudando só o sufixo de estágio; feature nova recebe o próximo NNN. Mesma definição reforçada no fluxo de IA (dono conceitual da regra).

  • Bootstrap de app novo aponta para o mirror público, não o Forgejo privado: o checklist app novo e publicar docs mandavam copiar os templates de fonte.xadm.biz/.../src/branch/master/templates/… — o Forgejo privado, que dá 404 sem auth (bootstrap de app novo, inclusive por agente de IA, falhava ou improvisava de um clone local defasado). Agora o bootstrap é manifesto-driven como a /xadm-docs: baixa do mirror público docs.xadm.biz/toolchain/raw/…, ancorado no manifesto.json como fonte única, com nota de que fonte.xadm.biz é edição/hosting (privado) e consumo é sempre via mirror. Mesmo swap no link irmão de versionamento.

  • gitignore-flutter publicado no mirror: o templates/gitignore-flutter não estava no manifesto, então toolchain/raw/templates/gitignore-flutter dava 404 — o link da engenharia Flutter já apontava pra lá (404 latente) e o de stack apontava pro Forgejo privado. O Dockerfile passa a publicá-lo cru no raw/templates/ (artefato copy-once de bootstrap, fora do manifesto — cada app customiza o .gitignore, não há o que re-sincronizar), e stack.md aponta pro mirror.

0.16.10 - 2026-06-25

Corrigido

  • Release sem prompt — pré-flight: o pré-flight ainda pedia autorização porque (a) git describe/git rev-parse não estavam no allow-list e (b) usava substituição de comando $(git describe …), que o matcher de permissão recusa por princípio. Adicionadas as regras de leitura (git status/rev-parse/describe/log/echo) ao allow-list e ao template da skill, e documentado o veneno do $(...) (pegar o valor num passo, usar literal no próximo). Constituição v0.14.20.

0.16.9 - 2026-06-25

Adicionado

  • Release sem prompt (opt-in): seção "Permissões" no template da skill /xadm-release documentando o allow-list do .claude/settings.json (git add/commit -m/tag/push origin) para o release não pedir autorização — com o trade-off explícito (remove a rede de segurança; a garantia vira a REGRA Nº 2) e a dica de rodar cada git separado (compound com pipe não casa o allow-list). Aplicado neste repo (.claude/settings.json + skill local). Constituição v0.14.19.

0.16.8 - 2026-06-25

Alterado

  • CI Flutter mais rápido (auditoria dos 3 apps + central): a imagem ci-flutter agora traz clang/lld/cmake/ninja/pkg-config baked (native assets do PowerSync/sqlite3) — o app não instala mais toolchain nativa por run (~2m20 a menos no ci.yml). Os templates ci.yml/docs.yml ganharam o passo Cache do pub (~/.pub-cache, key por pubspec.lock) e a nota de que a toolchain vem na imagem. Constituição v0.14.17. Migração: app Flutter re-deriva o ci.yml (dropar o passo "Toolchain nativo") via /xadm-docs.
  • CI de docs mais rápido: o docs.yml ganhou cache de pip + npm (~/.cache/pip + ~/.npm) — mkdocs e mermaid passam a instalar do cache (sem re-download por run, ~20-35s/run). Avaliado e descartado assar numa imagem ci-docs: o lint-mermaid.mjs é ESM e não resolve módulo global (nem via NODE_PATH), e imagem nova só pelo mkdocs (~15s) seria over-engineering. Constituição v0.14.18.

0.16.7 - 2026-06-25

Alterado

  • Fábrica de CI (decisão 0003): a fonte das versões passou a ser a ci-images/matriz-baseline.json — a leitura agregada dos app.json do bucket foi removida. Ela criava um deadlock de bootstrap (o app.json chega ao bucket via docs.yml, que roda na imagem que a fábrica deveria ter buildado), travando o 1º app Flutter version-pinned (bi-transporte, flutter: 3.44.0). Adoção de versão nova = PR na baseline + push (a fábrica builda) antes de o app apontar o container:. Baseline já com flutter: 3.44.0; ci-images.yml sem o passo do bucket/DOCS_S3. Decisão 0003 ganhou nota datada; app-novo, engenharia/flutter e o runbook documentam a ordem. §6 do bi-transporte.

0.16.6 - 2026-06-24

Corrigido

  • Fábrica de CI (ci-images.yml): o docker build do job falhava com "Cannot connect to the Docker daemon" — o runner da org usa DinD por TCP (sem socket unix no job). O passo de build agora deriva DOCKER_HOST do gateway default do job (= daemon do DinD). Runbook fabrica-imagens-ci.md corrigido: o socket-do-host do passo 1 só vale para runner sem DinD.

0.16.5 - 2026-06-24

Alterado

  • templates/docs.yml: passo Cache do Gradle no bloco de javadoc (paridade com o ci.yml; o comentário já prometia mas não entregava) — todo app Java que gera Javadoc no CI de docs ganha o cache ao descomentar. Referência ao JDK deixou de citar versão fixa (era "JDK 21") e aponta a imagem ci-java:<v>. Constituição v0.14.16. (§6 de app Java.)

Corrigido

  • Imagem ci-java:<v> da fábrica de CI estava sem rclone — o docs.yml de app Java falhava no "Publicar no Garage" (rclone: command not found), apesar de o comentário do template anunciar "toolchain pré-instalada". Adicionado ao ci-images/Dockerfile.java (a ci-base e a ci-flutter já tinham). Requer rebuild+push da ci-java. (§6 de app Java.)

Revertido

  • O fallback de /commit.txt via .git/HEAD (introduzido na v0.16.4) quebrava o build no Coolify: COPY .git/HEAD falha com "/.git/HEAD": not found porque o Coolify não inclui o .git no contexto de build — o deploy não subia. /commit.txt volta a dev (cosmético conhecido); a receita em coolify.md virou aviso de "não leia o .git/HEAD no build — use Build Argument". O fix do export TAG no release.yml (v0.16.4) permanece — é independente.

0.16.4 - 2026-06-24

Corrigido

  • templates/release.yml (bloco opt-in de Release no Forgejo): a tag saía como var de shell sem export, então o python3 -c filho não a enxergava (KeyError: 'TAG' → corpo do POST vazio → 422). Agora export TAG=…. Também documentado que a escrita no repo (permissions: contents: write ou RELEASE_TOKEN) é obrigatória — sem ela dá 403 antes do 422. Constituição v0.14.15. (§6 do maxsul-pied-simples, 1º app a habilitar o bloco.)
  • /commit.txt carimbava dev: o Coolify não passa SOURCE_COMMIT como build-arg. O Dockerfile agora tem fallback que lê o commit do .git/HEAD (checkout destacado do deploy = SHA); .dockerignore deixa só o HEAD entrar no contexto.

Adicionado

  • Receita em infraestrutura/coolify.md para carimbar o commit do deploy via .git/HEAD quando o Coolify não passa SOURCE_COMMIT (opcional, para app que embute o commit; não é exigência da constituição).

0.16.3 - 2026-06-24

Corrigido

  • overrides-main.html e changelog.md agora são rastreados (publicados raw + manifesto) — os dois scaffolds da doc versionada (overrides/main.html do banner; docs/changelog.md da página "Mudanças") são estáticos-idênticos entre apps (como o checkstyle.xml), mas estavam fora do manifesto.json e do raw/ do site → davam 404 e a /xadm-docs não detectava defasagem nem conseguia re-baixá-los (só com checkout local do central). Adicionados ao RASTREADOS (auto-publicados em toolchain/raw/templates/ pelo Dockerfile) + destino documentado na skill /xadm-docs. Feedback de uso real via loop §6 (maxsul-pied-simples).

Alterado

  • release.yml: rótulo do artefato Flutter mais preciso — o comentário dizia "Flutter → bundle (apk/web)", misturando Flutter Web (que é deploy via Coolify, não artefato) com mobile/desktop (artefato distribuível → Release). Esclarecido: Web segue o caminho deploy (sem Release/asset); mobile (apk/IPA) e desktop (win/linux/mac) geram Release com asset. O como buildar cada alvo fica a definir quando surgir o 1º app (não normatizar no escuro, §1.2). Feedback de uso real via loop §6.
  • release.yml: token da Release configurável + permissions — o GITHUB_TOKEN automático do Actions costuma ser só Actions (não cria Release → 403). O bloco opt-in agora orienta declarar permissions: contents: write no job para elevar o auto-token e, se o instance restringir mesmo assim, usar um token dedicado da org RELEASE_TOKEN (escopo write:repository) — o curl usa RELEASE_TOKEN se existir, senão o GITHUB_TOKEN. Setup documentado em infraestrutura/forgejo. Feedback de uso real via loop §6 (maxsul-pied-simples).

0.16.2 - 2026-06-24

Alterado

  • Dogfood: o central usa as próprias skills de workflow — instaladas xadm-spec/refine-spec/plan/work/compound/meta-audit-work em .claude/skills/ (antes só a xadm-release); o CLAUDE.md recomenda o fluxo /xadm-* para feature não-trivial aqui. E o CI do próprio central (build-site.yml) passou a usar a imagem ci-base (antes montava git+python via apt a cada run). Mudanças internas — não alteram o site publicado.

0.16.1 - 2026-06-24

Corrigido

  • Build do site no Docker (deploy da v0.16.0) — o mkdocs build --strict do Dockerfile falhava porque o COPY seletivo do build stage não trazia da raiz o overrides/ (do theme.custom_dir — banner de versão antiga) nem o CHANGELOG.md (embutido pela página "Mudanças" via snippet). Adicionados os dois COPY. Build local passava; o contexto enxuto do Docker não.

0.16.0 - 2026-06-24

Adicionado

  • Release do Forgejo com artefato anexado (engenharia/versionamento) — no Forgejo tag ≠ Release: a tag sozinha deixava a aba Releases vazia e o jar sem proveniência. O templates/release.yml ganhou um bloco opt-in, stack-aware que, para app que distribui artefato (jar/CLI/worker), builda o artefato no CI e publica a Release (tag + notas da seção do CHANGELOG + asset anexado), via API do Forgejo por curl + secrets.GITHUB_TOKEN. O marco do que foi liberado passa a ser a Release (download reproduzível), não só a tag; o operador baixa o jar da aba Releases. Requer a imagem ci-java:<v> (a ci-base não tem JDK) e token com escopo de escrita em release. Skill /xadm-release e o modelo de distribuição atualizados. Feedback de uso real via loop §6 (maxsul-pied-simples).
  • Documentação versionada por release (decisão 0004 / spec 011) — cada tag vX.Y.Z publica um snapshot imutável da doc em docs-sites/<app>/<X.Y.Z>/, e um seletor de versão nativo do Material (extra.version.provider: mike) no topo lista as releases; a raiz abre na maior SemVer; master vira o preview dev/ (fora do dropdown). Implementado: templates/mkdocs.yml (provider) + templates/docs.yml (gatilho tags, site_url por-versão, publish na subpasta — nunca rclone sync da raiz) + novo scripts/publica-versao.py (monta versions.json+redirect na raiz via rcat, publicado no site) + sync-apps.sh (detecta api/ na versão default). Invariantes duros: app.json fica na raiz (senão quebra a fábrica de imagens); forward-only (sem backfill). Spike confirmou na fonte do Material que o site_url precisa terminar na versão. Adoção por app é pós-release (o docs.yml baixa o publica-versao.py do site). Dogfood do central e poda de storage: diferidos (spec 012 + brief).

  • Página "Mudanças" (CHANGELOG) no site de cada app — o CHANGELOG.md da raiz do repo agora aparece no site, em entrada de nav própria no topo, embutido via pymdownx.snippets (--8<-- "CHANGELOG.md", fonte única §1.8/§1.9 — sem cópia, sem editar em dois lugares). templates/mkdocs.yml ganhou a entrada; novo scaffold templates/changelog.md. Aplicado no central (dogfood) e nos pilotos. Casa com a doc versionada (spec 011): cada snapshot de versão mostra o changelog daquela release.

Alterado

  • release.yml passa a usar a imagem de CI ci-base (decisão 0003) — faltou na migração inicial (só ci.yml/docs.yml tinham ido): rodava em node:22-bookworm-slim e instalava git+python via apt a cada release (~22s). Agora usa ci-base (já traz git+python+curl) — só roda o valida-release.py. −~22s por release.

0.15.0 - 2026-06-22

Adicionado

  • Fábrica de imagens de CI por stack+versão + cache do Gradle (decisão 0003) — o runner Forgejo da org é efêmero e os templates ci.yml/docs.yml montavam o ambiente do zero a cada run (apt/pip, download de JDK e git clone do Flutter SDK — o maior custo). Agora: imagens por stack+versão servidas no registry do Forgejo (ci-base, ci-java:<v>, ci-flutter:<v> com o SDK baked), montadas por uma fábrica central (ci-images/ + .forgejo/workflows/ci-images.yml) que lê o campo novo toolchain dos app.json agregados do bucket (sem token de Git entre repos) + uma baseline, e builda/empurra a matriz. Os templates apontam o container: da stack; actions/cache@v4 cacheia o Gradle. Java 25 fixado como LTS da casa (stack). Pré-requisitos de infra (do operador): runner buildando imagem + push pelo endereço interno do registry (dribla o Traefik/499) + token de pacote da org — runbook em infraestrutura/fábrica-imagens-ci; o workflow já vem parametrizado (CI_REGISTRY_HOST/REGISTRY_TOKEN). Consolida o feedback de CI/deploy do piloto Flutter (loop §6): subosito quebrado, drift da versão do SDK (fonte única no .fvmrc, sem FLUTTER_VERSION no Coolify), asset gerado antes do test, config pública hardcode vs build-arg.
  • toolchain obrigatório no app.json para app Java/Flutter (decisão 0003) — o validador agora falha se um app de stack Java/Micronaut não declarar toolchain.java (ou Flutter/Dart sem toolchain.flutter): sem a declaração a fábrica não builda a imagem-versão e o container: do CI aponta para imagem inexistente, quebrando com erro de pull obscuro. Falha cedo e clara em vez de tarde e confusa. App docs-only (ci-base, sem versão) não declara. Documentado no contrato do app.json (publicar-docs), engenharia e checklist app-novo.
  • Nota fixa "Build Argument × Environment Variable" no Coolify (infraestrutura/coolify + eco em engenharia/flutter) — pega-pé recorrente (mordeu 3× numa sessão: FLUTTER_VERSION, SENTRY_DSN): valor que o build embute na imagem (--dart-define, ARG) precisa ser Build Argument (+ "Available at Buildtime"), não env de runtime — como runtime chega vazio ao bundle e o app sobe sem ele, sem erro. Mecânica bidirecional canônica em coolify.md (o sentido inverso — segredo de runtime como build arg vaza como ARG — é o caso dos DOCS_S3_*); eco específico de --dart-define no flutter.md. Feedback de uso real via loop §6.

0.14.1 - 2026-06-22

Adicionado

  • Conformidade de engenharia no loop de sincronização (constituição §6 + /xadm-docs) — as regras de engenharia (engenharia/*) eram lidas ao vivo pelas skills mas ficavam invisíveis ao /xadm-docs, que só olhava o manifesto de templates; um app não detectava defasagem de regra de engenharia (e o raw das páginas dava 404). Agora o site publica as páginas de engenharia também cruas (.../toolchain/raw/engenharia/<stack>.md) e o /xadm-docs ganhou o passo 3b: ao detectar bump, re-audita o código da stack do app contra a regra vigente (exit codes, libs, observabilidade, gate, definição de pronto) e propõe correções com aprovação — re-auditar, não re-baixar. As páginas não entram no manifesto por desenho (regra viva lida ao vivo ≠ artefato copiado que envelhece). Feedback de uso real via loop §6.
  • Exit code 4 ocupado/lock na taxonomia de CLI/worker (engenharia/java) — a lista 0 ok · 1 parcial · 2 config/auth · 3 externo não cobria "execução concorrente serializada por lock; nada feito; seguro repetir", desfecho recorrente em job reentrante (cron + gatilho sob demanda dividindo estado). Fixado também que a lista é o contrato canônico da casa (app não inventa código; desfecho novo entra por §6) e que o app documenta a saída no runbook de operacao/. Feedback de uso real via loop §6 (auditoria maxsul-pied-simples, que já shippou exit 4 na sua ADR 0003).

Corrigido

  • Frontmatter YAML nos 6 templates de skill de workflow (xadm-spec/refine-spec/plan/work/compound/meta-audit-work) — faltava o bloco --- name / description --- que o Claude Code usa para descobrir e rotear a skill (as xadm-docs/xadm-release já tinham). Sem ele, ao copiar verbatim para o app a skill aparecia com a description virando o comentário-cabeçalho e a invocação quebrava. Feedback de uso real via loop §6. description no formato "o que faz + Use quando…".

0.14.0 - 2026-06-22

Adicionado

  • Conjunto de skills de workflow X-Adm (constituição v0.13.0; decisão do Gustavo, 010c §13): xadm-spec → xadm-refine-spec → xadm-plan → xadm-work → xadm-compound, modelado no ACT mas próprio da casa. Stack-aware — detectam a stack e seguem a base de conhecimento da Engenharia daquela stack. xadm-work não commita (REGRA Nº 2); xadm-compound destila para docs/ e refina a base de conhecimento (loop §6). Templates rastreados no manifesto (o /xadm-docs + o hook de sessão acusam defasagem). Catálogo na IA e Claude Code.
  • Skills de workflow reescritas a fundo + xadm-meta-audit-work (constituição v0.14.0; Gustavo comprou o ACT PRO vitalício e quis o workflow da casa "o mais parecido possível, inclusive os insights"): as 5 skills ganharam a profundidade do ACT adaptada à casa — contrato duro + invariantes que falham o workflow (xadm-work), map_flows/preview_outline/complexidade adaptativa (xadm-spec), regras não-negociáveis + formato de achados + review gate (xadm-refine-spec), pesquisa + style contract + checklist de qualidade (xadm-plan), extração paralela + quality bar (xadm-compound); preservados os inegociáveis X-Adm (não-commitar, destilar p/ docs/, gate por stack, pt-BR, definição de pronto §6). Nova /xadm-meta-audit-work audita um run da /xadm-work (confere não-commit, reconciliação do plano, gate da stack e a linha §6).
  • Princípio de engenharia "Simplicidade primeiro (sem over-engineering)" na Engenharia — busque o caminho mais simples que satisfaz a necessidade real e presente; abstração/camada/generalização só com necessidade concreta (YAGNI). As skills de workflow ecoam o princípio onde a IA decide escopo/desenho/implementação (xadm-spec, xadm-plan, xadm-work) e a xadm-refine-spec ganhou a 7ª dimensão de checagem (pega over-engineering já na spec). Irmão de engenharia do "enxuto por padrão" da constituição §1.5 (que vale para a doc).

0.13.0 - 2026-06-19

Adicionado

  • Área Engenharia construída (docs/engenharia/) — o lado "como construir" do padrão: Stack da casa (matriz app→stack + defaults opinativos), páginas por stack (Java/Micronaut servidor com guarda de fronteiras, Java app simples/CLI/worker, Flutter cliente), CI, gates e testes, e versionamento + health check. (Phases 1–5 do plano de Engenharia.)
  • checkstyle.xml + suppressions.xml centralizados (templates/, rastreados no manifesto, publicados em /toolchain/raw/) — fonte única de estilo Java; para de copiar app-a-app.
  • Seção "Critérios de aceite e teste" no template de etapa (doc-projeto.md) + marcador "regras arquiteturais guardadas por teste/lint" no livro — a ponte para quem valida.

Alterado

  • Regras de engenharia movidas da constituição para a área Engenharia (CI por stack, SemVer/release, health check, branch master, níveis de teste, deploy) com ponteiro curto — a constituição fica menor; o piso da definição de pronto permanece (§6).
  • Home (index.md) reescrita — declara a constituição de arquitetura, engenharia e documentação, com os dois caminhos (Documentação · Engenharia); "Tudo numa página" sai do menu de abas; separador no menu entre as áreas de teoria e prática; menções a ZIM/ERP sem adjetivo.

0.12.0 - 2026-06-19

Adicionado

  • Portal em duas áreas distintas: Documentação × Engenharia (constituição v0.12.0; decisão do Gustavo). O site reorganiza em abas (navigation.tabs): Documentação (constituição, templates, publicar, app-novo, decisões), Engenharia (NOVA) e Transversais (IA, infraestrutura, glossário). As pastas no source espelham: docs/documentacao/, docs/engenharia/, docs/transversais/. A constituição passa a se chamar "Constituição da Documentação e Engenharia"; o site, "Padrões da Plataforma X-Adm".
  • Área Engenharia + Stack da casa (docs/engenharia/): matriz opinativa app→stack (Micronaut servidor · +Thymeleaf view simples · Flutter cliente/web/mobile · Java puro app simples/CLI · ZIM legado) + defaults transversais (package-by-feature universal, OkHttp, Gradle KTS, JUnit5+WireMock, BigDecimal, Logback, PostgreSQL+Flyway, picocli). Default forte + exceção documentada.
  • .gitignore Flutter de referência (templates/gitignore-flutter; feedback via loop §6). Corrige dois bugs que o template legado da org propagava: pubspec.lock agora versionado num app (build reproduzível, sem *.lock); FVM usa .fvmrc versionado (sem o legado !.fvm/fvm_config.json). Referenciado na Stack da casa.

Alterado

  • Toolchain de máquina migrado para /toolchain/ (constituição v0.12.1). Os artefatos que os apps baixam no CI (validadores, hooks, constituicao-versao.txt, raw/, manifesto.json) saem de /padroes/ para /toolchain/ — namespace neutro às duas áreas. O Dockerfile dual-publica (/padroes/ segue vivo na transição → apps não quebram, re-derivam oportunisticamente). URLs de página antigas (/padroes/X) ganham redirect (mkdocs-redirects) para a área nova.
  • Campo entregue: true|false na etapa (constituição v0.11.1, §2; feedback via loop §6). Separa a entrega da feature do status do doc no Resumo Executivo — permite "design aprovado, build pendente" (status: aprovado + entregue: false). Opcional e retrocompatível: sem o campo, cai no heurístico legado (status aprovado → entregue). Toca visao-tecnica.py, valida-frontmatter.py, constituição §2 e o template de etapa.
  • Convenção .ia/ para andaime (constituição v0.11.1, §1.9; feedback via loop §6). Artefato de trabalho (spec, plano) vive em .ia/NNN-*.md, numerado por repo, fora de docs/ (não é conteúdo publicado).

0.11.1 - 2026-06-19

Adicionado

  • Template Guia do código (templates/guia-do-codigo.md) (constituição v0.11.0, §2/§4; feedback via loop §6 dos pilotos BI Transporte). Página Dev padrão de todo app com código: narrativa autorada da organização do código, com blocos por stack (Java package-by-feature / Flutter feature-first) e o marcador opcional de inventário.
  • xadm.css centralizado (templates/xadm.css) (constituição v0.11.0; feedback via loop §6). A identidade visual vira fonte única no central (antes duplicada por app) — inclui a regra .md-typeset a:not(.headerlink) (links de conteúdo com burgundy + sublinhado, antes pouco identificáveis). Apps copiam do central; mudança visual num lugar só.

Alterado

  • Nav do template por ciclo de vida + seções Pré-projeto/Projeto (constituição v0.11.0, §2; feedback via loop §6). O mkdocs.yml canônico passa a recomendar Resumo → Pré-projeto → Projeto → Operação → Dev → Público → Etapas → Decisões → Glossário, com Projeto = especificação e Etapas = execução explicitados (antes "Etapas" virava catch-all). O resumo-executivo.md ganha o bloco "O que você encontra aqui".
  • Hook visao-tecnica.py remove <!-- GERADO: inventario --> não preenchido (feedback via loop §6). O inventário de classes é preenchido por um passo Javadoc/dartdoc no docs.yml do app; sem o passo, o hook compartilhado remove a linha (nunca embarca o marcador cru) — contrato documentado na publicar-docs.md.
  • Definição de pronto: a verificação exercita a plataforma real (constituição v0.10.15, §6; feedback via loop §6). O piso de teste ganha que a verificação tem que exercitar a plataforma/runtime real (Web, mobile, o build do app), não só --strict/fixture — o risco recorrente em mudança de migração/toolchain é o gate "passar" sem tocar o sistema de verdade.
  • Branch principal padronizado em master (constituição v0.10.17, §5; feedback via loop §6). Os templates docs.yml/ci.yml vinham com branches: [main] e um comentário pedindo ajuste manual — o passo que falhava: num app em master, a CI nunca rodava em silêncio (só a release, por tag). Agora o template já vem branches: [master], sem ajuste por repo, e a convenção está na §5.
  • REGRA Nº 2: skills que commitam por padrão rodam em no-commit (constituição v0.10.16, REGRA Nº 2 / §6; feedback via loop §6). Skill de execução que commita sozinha (ex. ACT act-workflow-work, que commita por fase) deve ser invocada sempre com a flag de não-commitar (--do-not-commit) — delegar a execução não delega a decisão de commit, que continua do dev ou da /xadm-release.
  • /health: status aceita liveness truthy (versionamento.md; auditoria do piloto BI Transporte). O valor exato deixou de ser normativo — "ok", "UP", etc. valem; o /health nativo do Micronaut ("UP") está conforme, sem remapear. Contrato segue: 200 + status vivo + versao legível.
  • /health do Flutter web responde {status, versao}, não o version.json cru (versionamento.md; auditoria do piloto BI Transporte Flutter). A receita por stack contradizia a §5 (que já exige o shape inclusive no Flutter web): o nginx monta o {status, versao} lendo a versão do version.json; o /version.json segue como endpoint separado do auto-update.
  • Versão em runtime nunca é literal hardcoded + receita de Java CLI (versionamento.md; feedback via loop §6 do xadm-pied-cliente). Princípio explícito: a versão em runtime vem sempre do manifesto do release, nunca de um literal no código (literal mente e drifta, porque a /xadm-release só toca manifesto+CHANGELOG). Receita nova de Java CLI (picocli): --version via IVersionProvider lendo o version.properties, não @Command(version="...").
  • CI de docs falha cedo se faltar DOCS_S3_* (templates/docs.yml; feedback do piloto). Guarda no passo "Publicar no Garage": secret vazio/ausente aborta com mensagem clara, em vez do críptico no such host do rclone após ~3min de retry.

Corrigido

  • Banner de supersessão renderizava o número errado (scripts/valida-frontmatter.py, frontmatter-cabecalho.py, templates/decisao.md; auditoria do piloto). superado-por: 0016 sem aspas era lido como octal pelo YAML (0016 → 14), e a decisão obsoleta mostrava "superada pela 14" no site — e o validador checava a cadeia contra a decisão errada, em silêncio. Agora o validador falha se superado-por/supersede vier sem aspas, o template mostra "NNNN" e o hook renderiza 4 dígitos.

0.11.0 - 2026-06-18

Adicionado

  • projeto/mapeamento.md opcional (constituição §2/§5): fonte embutida do cap. 4 do livro (mapeamento entrada↔dados — "origem → destino + transformação"), fragmento sem frontmatter, isento no validador (como modelagem.md). Template novo.

Alterado

  • Release: versão Java também em build.gradle.kts + bootstrap de release mais visível (constituição v0.10.14; feedback via loop §6 — arquétipo Java CLI). O valida-release.py e a skill /xadm-release passam a ler a versão de gradle.properties ou do build script (build.gradle.kts/build.gradle, linha de topo version = "..."), não só de gradle.properties. O app-novo ganhou a instalação da skill /xadm-release (faltava — só listava a /xadm-docs) e a nota de que o CHANGELOG.md nasce na 1ª release (inferido do git log, cobre o histórico); versionamento.md idem. Fecha o gap do PoC que adotou docs mas pulou o wiring de release.

  • Modelo de dados generalizado: banco E/OU contrato de saída (constituição v0.10.13, §2/§5; feedback via loop §6 — arquétipo CLI sem banco). modelagem.md deixa de ser "só projeto com banco": vale também para o contrato dos artefatos de saída/integração (JSON, payload), e o cap. 3 do livro acomoda os dois. Corrige um over-fit ao piloto Java/Postgres.

Corrigido

  • Scripts publicados também em raw/scripts/ (sha do manifesto verificável) (feedback via loop §6). O manifesto.json traz o sha do arquivo cru dos scripts, mas o Dockerfile só publicava a forma carimbada (/padroes/<script>.py, versão na 1ª linha) — o sha nunca batia e raw/scripts/ dava 404. Agora o Dockerfile publica também a forma crua em /padroes/raw/scripts/<script> (casa com o manifesto), mantendo a carimbada para execução. Contrato documentado em publicar-docs.

0.10.0 - 2026-06-17

Adicionado

  • Definição de pronto unificada (mudou código → teste + doc no mesmo PR) (constituição v0.10.12, §6; feedback via loop §6). Fecha a assimetria: o §5 já pedia doc-no-mesmo-PR, mas faltava a metade simétrica de teste, e nenhuma era item de fechamento. O §6 passa a fixar o piso unificado — teste proporcional ao risco (mín.: nenhuma regressão sem teste de regressão) + doc do estado atual (mín.: nenhuma mudança de comportamento sem doc); pular metade é decisão explícita (REGRA Nº 3). É disciplina de fechamento + o gate do ci.yml, não um gate que detecta "doc seguiu código" sozinho. A doutrina detalhada de teste (níveis, e2e em fronteira de segurança, paridade em refactor) fica para a área de Engenharia (futura). Item de fechamento condicionado a "mudou código" em claude-regras.md/CLAUDE.md.

0.9.2 - 2026-06-17

Adicionado

  • Ghost mode nas mensagens de commit geradas pela IA (constituição v0.10.8, §6; feedback via loop §6). A mensagem que o agente escreve para o dev copiar sai sem Co-Authored-By, "Generated with" ou qualquer atribuição de IA — regra que sobrepõe o default do harness (que carimba co-autoria). Antes só a /xadm-release tinha ghost mode; agora vale para toda mensagem gerada. Em templates/claude-regras.md (REGRA Nº 2), §6 e no CLAUDE.md do central.
  • Oferta §6 no fechamento: obrigatória, acoplada ao commit e afirmativa (constituição v0.10.9, §6; feedback via loop §6). A regra existia em prosa mas dependia de o agente lembrar — e ele pulava. Agora a linha §6 (§6: nada a reportar ou §6: candidato a feedback — <o quê>) sai sempre junto da mensagem de commit, na mesma resposta; a ausência dela é sinal visível de passo pulado, não silêncio. Em templates/claude-regras.md (REGRA Nº 2), §6 e no CLAUDE.md do central.

  • Guia "Como compilar e testar localmente" obrigatório no nível Dev (constituição v0.10.10, §2; pedido do Gustavo). App que executa traz em docs/dev/ um guia de como rodar localmente (modo simulação): pré-requisitos (runtime/versão, Docker p/ banco), passos e recomendações de ambiente. O detalhe fino por stack é da área de Engenharia (futura); aqui fica o requisito-de-existir.

Alterado

  • §1.9 — destilar é obrigatório; apagar o andaime é recomendado, não obrigatório (constituição v0.10.11; refino pós-auditoria adversarial). Ao concluir uma spec/trabalho, destilar o conhecimento durável para docs/ é obrigatório (inclui o que ferramentas como /compound geram nos docs); apagar o artefato .ia/ deixa de ser obrigatório — pode ficar versionado como andaime/histórico, desde que o durável já esteja em docs/. Alinhado em templates/claude-regras.md.

Corrigido

  • <!-- HUMANO --> pendente falha o build em página status: aprovado (constituição v0.10.11, §2; auditoria adversarial). Antes só RECONCILIAR falhava — um livro (projeto/index.md) cheio de HUMANO buildava verde e publicava em branco (o comentário some no HTML). Agora o hook visao-tecnica.py falha simétrico ao RECONCILIAR; em rascunho/em-revisão é WIP, preservado.

0.9.1 - 2026-06-16

Corrigido

  • templates/mkdocs.yml (constituição v0.10.2): o comentário do hook visao-tecnica.py ainda descrevia o modelo antigo (montar visao/index.md a partir de capitulo:) — contradizia a própria 0.10.x, em que o livro é autorado (projeto/index.md) e capitulo: é legado. Comentário atualizado para "processa os marcadores do livro autorado". Feedback via loop §6.

Adicionado

  • Lint de diagramas Mermaid no CI (constituição v0.10.4, §5; feedback via loop §6). A constituição manda Mermaid (ER em modelagem.md, fluxos nas etapas), mas diagrama com erro de sintaxe renderiza cru no site e passa pelo --strict — caso real: erDiagram com uk usado como TIPO renderizou cru por 6 versões. Novo lint-mermaid.mjs extrai cada bloco ``mermaid e rodamermaid.parse(Node + jsdom, **sem Chromium**); diagrama que não compila **falha o build**. Ligado nodocs.yml(apps) e nobuild-site.yml` (central); publicado e carimbado.
  • tipo: livro para a Documentação Completa (constituição v0.10.5, §4; feedback via loop §6). O livro (projeto/index.md) era forçado a se declarar tipo: projeto — e não é uma etapa. Agora tem tipo próprio; modulo: não se aplica (o livro é do app inteiro); o valida-frontmatter.py espera tipo: livro nesse arquivo (e segue isentando projeto/modelagem.md, fragmento sem frontmatter).
  • Template do livro + guia de modelagem (constituição v0.10.6, §5; feedback via loop §6). templates/projeto-index.md (ex-visao.md) publica o esqueleto dos 8 capítulos com o embed do modelagem.md e o <!-- GERADO: changelog --> no lugar. E o templates/modelagem.md cravou o meio (antes improvisado caso a caso): ER Mermaid só para o overview de relacionamentos; o dicionário por tabela vai em tabela Markdown (coluna | tipo | chave | nulo? | desde | nota), porque o erDiagram não expressa NOT NULL nem chave composta e fica ilegível em tabela larga; fluxo de dados opcional.

Alterado

  • Ordem recomendada do nav do app (constituição v0.10.7): no templates/mkdocs.yml, as duas portas (Resumo Executivo, Documentação Completa) primeiro; depois referência (Dev/API, Operação, Público); depois histórico (Etapas, Decisões); Glossário no fim.
  • Massa de dados: regra invertida para o modelo privado-por-padrão (constituição v0.10.3, §5; feedback via loop §6). O valida-frontmatter.py bloqueia massa de dados (.xlsx/.csv/.sql/...) só em docs/public/ (a superfície exposta), não mais "em todo docs/ fora de anexos/" — a mensagem antiga ainda dizia "docs/ é público", desalinhada do §5. Em pasta privada é livre; risco declarado: até o login (spec 007), o portal serve docs/ aberto exceto privado/, então dado confidencial deve ficar em privado/, sob responsabilidade do autor.

0.9.0 - 2026-06-16

Adicionado

  • Modelo de dados obrigatório para projeto com banco: docs/projeto/modelagem.md (ER Mermaid consolidado, fonte da verdade do schema, evoluído no mesmo PR), embutido no livro via pymdownx.snippets (constituição §5).
  • checa-modelagem.py: aviso opt-in no CI de código quando o diff mexe numa migration sem tocar o modelagem.md (com suspeita de DROP/"legado" no SQL), tolerante e nunca fatal — publicado no site e carimbado.

Alterado

  • Documentação Completa autorada no estado atual (constituição v0.10.x): o livro deixa de ser montado por aspecto das etapas e passa a ser um esqueleto autorado (projeto/index.md) que mostra o sistema como ele é hoje, em ordem lógica que termina nos contratos públicos. O hook visao-tecnica.py só injeta marcadores (etapas no Resumo Executivo, changelog no livro) e falha o build em <!-- RECONCILIAR --> não resolvido. Configuração entra no livro, deploy fica em operacao/, capitulo: vira legado.
  • valida-frontmatter.py: supersessão de decisões verificada em cadeia (obsoleta tem que chegar a uma viva — referência quebrada/ciclo/dead-end = erro) e docs/projeto/modelagem.md isento da validação de frontmatter.

0.8.0 - 2026-06-15

Alterado

  • Constituição v0.9.0 — Documentação Completa por ASPECTO + Resumo Executivo das etapas (feedback do Gustavo sobre a novo-4): o livro empilhava etapas inteiras e virava copia-e-cola — porque os capítulos são aspectos (arc42) mas as folhas são etapas que cruzam todos. Agora o hook extrai as seções ## de cada etapa e as reagrupa por capítulo (o "Modelo de dados" reúne o de todas as etapas, as "Decisões" vêm de decisoes/), com atribuição "(Etapa NN)" — o livro arc42 que se lê por aspecto. Roteamento pelo nome da seção (canônicas do template de etapa), capitulo: vira fallback. E o Resumo Executivo (index.md) ganha o marcador <!-- etapas -->: o hook injeta "entregue/planejado" do campo novo entrega: (frase de negócio) + status de cada etapa. Templates doc-projeto.md e resumo-executivo.md atualizados; §2/§4 + app-novo.

Adicionado

  • Constituição v0.8.3 — REGRA Nº 3: deferir é explícito, não silencioso. A migração oportunista (§1.6) é legítima, mas vira escotilha silenciosa quando o "deferi reescrever o conteúdo das etapas para a barra técnica nova" passa como rodapé. Nova regra de IA (claude-regras.md + CLAUDE.md do central): adiar trabalho que o padrão recomenda é uma decisão — declarada em voz alta no fechamento ("deferido X porque…"); e se o repo ainda não publicou (sem slug no ar), o rename/redirect custa zero → fazer agora, não deferir como legado. Gancho na §1.6 e passo de fechamento na skill /xadm-docs. Feedback via loop §6.

Corrigido

  • Constituição v0.8.2 — manifesto regenerado a cada bump (inclusive text-only): um bump que mexe só no texto da constituição (como o v0.8.1) não tocava artefato rastreado, então o --check passava e o campo manifesto.constituicao ficava atrás da versão vigente (0.8.0 vs 0.8.1) — a /xadm-docs que confiasse nele subdetectaria mudanças. Prevenção: o gera-manifesto.py --check agora falha se manifesto.constituicao != versão vigente; como o CI do central roda --check, todo bump passa a exigir --update (que re-carimba o campo) para passar — o esquecimento fica impossível. §6 atualizado. Feedback via loop §6.

0.7.0 - 2026-06-15

Alterado

  • Constituição v0.8.1 — etapa de projeto tecnicamente completa (§2): avaliação do doc fundador do piloto (PROJ-2026-001) mostrou que dava pra ler mas não dava pra implementar — faltava o modelo de dados (ER, tabelas, colunas, chaves), os contratos e a config; o template ainda dizia "não liste toda coluna". Novo critério: cada etapa é tecnicamente completa para o seu escopo (um dev/IA que nunca viu o código implementa o que ela introduz/muda), por composição sem repetir (referencia o que herda, re-enuncia só o que altera — §1.4); o livro (Documentação Completa) compõe o desenho completo do sistema. Seções de completude técnica no §2 (arquitetura, modelo de dados ER+tabelas+colunas+chaves, contratos, fluxos+estados, config, qualidade), com a navalha do §1.2 (design e contrato duráveis, não spec linha a linha). Template doc-projeto.md reescrito (modelo de dados com colunas/tipos/chaves; seções Contratos/Configuração/Qualidade).

  • Constituição v0.8.0 — "Documentação Completa" (o livro) + Resumo Executivo + Etapas do Projeto (feedback do Gustavo sobre a novo-3): a antiga "Visão técnica" era só links e não virou livro — agora o hook visao-tecnica.py concatena o CONTEÚDO das folhas por capítulo (rebaixa títulos, reescreve links/imagens, preserva Mermaid), virando a página Documentação Completa que se lê de cima a baixo. A home do app vira Resumo Executivo (porta do diretor: problema + solução sem jargão → Documentação Completa). E projeto/ deixa de ser "PROJ-AAAA-NNN": são Etapas do ProjetoNN-titulo.md (duas casas, sem PROJ-/ano), avulso em projeto/diversos.md. §2/§3/§5 + templates (mkdocs nav, doc-projeto, visao-capitulo) + app-novo atualizados. Legado PROJ- aceito até migração oportunista.

  • Constituição v0.7.3 — imagem de manual público vai em docs/public/img/: a guarda de public/ (constituição §5) trata ![](...) como referência, então um print em docs/img/ (fora de public/) falhava — corretamente: imagem fora de public/ 404 quando o portal trancar. Convenção alinhada: prints do manual (que é público) vivem em docs/public/img/; docs/img/ fica para imagens de páginas internas (raras — diagramas são Mermaid). §2/§3 + screenshots-manual.md

  • template do manual atualizados; mensagem da guarda agora cita imagem. Feedback do bi-transporte-xls via loop §6.

0.6.0 - 2026-06-15

Adicionado

  • Constituição v0.7.2 — referência de API gerada pelo CI de docs (§5): TODA doc, inclusive a ref de API, é gerada e publicada pelo pipeline de docs, nunca pelo build/deploy do app. O gerador roda antes do mkdocs build, para dentro de docs/ → o link é Markdown normal e o --strict valida (acaba o anti-padrão do HTML-cru que driblava o strict e 404 no preview, e a duplicação por repo). Split de visibilidade: Javadoc/dartdoc (árvore de classes) → interno docs/dev/api/; OpenAPI (contrato) → público docs/public/api/ embutido via mkdocs-swagger-ui-tag (spec gerado do código, ex. micronaut-openapi — não do app deployado). templates/docs.yml ganha o passo "Gerar referência de API" por stack; templates/public-api.md novo; pins no toolchain. Corrige também: o docs.yml não instalava o mkdocs-print-site-plugin (bug da v0.6.0). Feedback do bi-transporte-xls via loop §6.

  • Constituição v0.7.1 — modelo de acesso SIMPLIFICADO (supera o v0.7.0): o v0.7.0 (frontmatter publico: + build duplo + dois domínios) foi commitado mas nunca shipou — o Gustavo simplificou: docs/ privado por padrão; o público vive em docs/public/. O que é público é o que está na pasta public/ (public/index, public/manual/, public/api/swagger) — sem marcação por página, sem build separado, um site só, zero infra. O manual do usuário e a API exposta passam a morar em public/. Guarda: o validador falha se uma página em public/ linkar para fora de public/ (senão quebraria quando o portal trancar). anexos/privado/ segue excluído do build (guarda do que é sensível enquanto não há login). Toolchain do padrão (/padroes/) é pública por design (CIs dependem). Decisão do Gustavo: adiar dois domínios e login — viram specs futuras 006 (dois domínios) e 007 (Google auth); a 005 fecha aqui. Fase 3/4 de .ia/005.

  • Constituição v0.6.1 — validador fresco (validador stale é falso atestado): os scripts publicados imprimem na 1ª linha a versão da constituição que implementam (carimbada no publish pelo Dockerfile); a skill /xadm-docs (e toda validação local) sempre baixa fresco e confere versão impressa == vigente antes de confiar no "0 erros" — nunca reusa cache de turno. Os scripts (valida-frontmatter.py, valida-release.py, frontmatter-cabecalho.py, visao-tecnica.py) entram no manifesto.json numa seção scripts à parte dos templates: mudar um script obriga bump da constituição (o --check falha), o que torna o carimbo confiável. Origem: um validador da era 0.5.5 deu "0 erros" numa migração a 0.5.20, dando conformidade falsa (feedback §6).
  • Constituição v0.6.0 — Visão técnica (espinha narrativa): os seis níveis são bons para consulta, mas uma pilha de folhas não se lê como livro. A Visão técnica é uma página de leitura ordenada montada no build a partir do campo capitulo: de cada folha (hook scripts/visao-tecnica.py, on_files + File.generated), na ordem de um esqueleto canônico (9 capítulos, negócio → técnico) — restaura o "ler de cima a baixo para entender" e a porta do diretor, sem desfazer a granularidade (as folhas seguem no seu nível). Plugin mkdocs-print-site-plugin (2.8) gera a página-única/PDF. Intro de capítulo opcional (docs/visao/NN-<capitulo>.md, templates/visao-capitulo.md). Origem: auditoria arc42×seis-níveis (.ia/004/005). Fase 1 da evolução (.ia/005).

Alterado

  • §5 invertido ("docs/ privado por padrão; público em docs/public/") + as três classes de acesso registradas. §2/§3: o manual do usuário (nível 6) passa a viver em docs/public/manual/; estrutura ganha a pasta public/. Validador: reconhece public/manual/ (tipo manual) e ganha a guarda de public/ (link que sai de public/ falha).
  • §1.7 reescrito: de "pronto para IA" para "dois modos: consulta E compreensão" — otimizar só a consulta é a regressão típica da doc-de-folhas.
  • §4: novo campo capitulo: (opcional; enum do esqueleto; validador erra em valor inválido — um typo sumiria a folha do livro).
  • Hook e plugin distribuídos aos apps: templates/mkdocs.yml (hook + print-site + nav), templates/docs.yml (curl do hook), Dockerfile (publica em /padroes/), requirements.txt (pin do print-site), app-novo.md (passo de adoção). Manifesto regenerado.

0.5.0 - 2026-06-13

Adicionado

  • decidido_em: no frontmatter de decisões (constituição §4) — data em que a decisão foi tomada, distinta de atualizado: (última edição). Cumpre a promessa de "retrato datado" quando o registro nasce retroativo numa migração. Opcional no validador (só confere formato AAAA-MM-DD se presente, para não quebrar decisão legada). Feedback do bi-transporte-xls via loop §6.
  • Constituição v0.5.20 — 9 mudanças da auditoria arc42×seis-níveis (BI Vantroba; pauta §6, todas avaliadas e aprovadas pelo Gustavo):
  • Hook scripts/frontmatter-cabecalho.py renderiza Status · Responsável · Atualizado em no corpo de cada página (o frontmatter sumia no build) e abre decisão obsoleta com aviso de supersessão. Publicado no site e baixado pelo docs.yml do app (igual ao validador); wired nos dois mkdocs.yml + Dockerfile. Constituição §6. (propostas #3 e #9 — a data vem do atualizado:, sem o plugin git-revision-date, que quebraria com o .git fora do build.)
  • navigation.path (breadcrumbs) nos dois mkdocs.yml — "onde estou" ao chegar via busca. (#6)
  • Contrato do Javadoc não-órfão: docs.yml falha se site/api/ existir sem nenhuma página linká-lo; receita em publicar-docs.md + dica no template. Constituição §5. (#1)
  • Template opcional templates/riscos.md (risk register transversal, consolida por link). Constituição §5. (#8)
  • Princípio anti-drift no §1.9 — um fato, um dono canônico; as demais páginas linkam (ou pymdownx.snippets), não copiam. (#7)
  • Mapa ADR-legado → decisão NNNN na 1ª migração arc42→seis-níveis (app-novo.md + skill /xadm-docs). (#10)

Validação

  • valida-frontmatter.py ganhou: aviso (não-fatal) sobre identificador de código volátil em título (*Test/Bulk* etc.) (#4); e erro quando a tabela de decisões de um doc de projeto reafirma um status que contradiz a decisão real (a decisão é a fonte única, §1.9/§5) (#5). Coluna "Status" removida do template doc-projeto.md.

Alterado

  • Constituição v0.5.19 — §1.4 e §2 passam a distinguir correção factual de superação num registro de decisão: fato incidental errado sobre o código (número, property inexistente) corrige-se em-lugar com nota datada; só premissa/raciocínio errado (a escolha poderia ter sido outra) exige superação (status: obsoleto + superado-por:). Antes, a regra "não se reescreve, supera-se" era absoluta e forçaria superar uma decisão por causa de um número errado.
  • §2 (Decisão) — "Alternativas consideradas" lista só as realmente deliberadas; reconstruir alternativas nunca cogitadas (comum em registro retroativo) é inventar deliberação (§1.2). Eco no template templates/decisao.md.

0.4.2 - 2026-06-13

Adicionado

  • Template templates/release.yml (constituição §6) — separa a validação de contrato de release (push de tag → valida-release.py) do ci.yml, que na v0.5.16 virou gate de qualidade e colidiu com o ci.yml antigo dos apps (que era o validador de release). Brecha do ho-scraper. Rastreado no manifesto; embutido em templates.md.

Alterado

  • Constituição v0.5.18 (§6, manifesto): redefinição de propósito de um template rastreado (mudar o que ele é, não só o conteúdo — ex. ci.yml release → qualidade) exige nota de migração no CHANGELOG e em app-novo.md; um re-pull cego quebra o app. Regra que faltava quando a 0.5.16 abriu a brecha do ci.yml.
  • Constituição v0.5.17 (§6): explicita dois workflows de códigoci.yml (gate de qualidade: análise estática + testes, push/PR) e release.yml (rede de segurança: valida-release.py, push de tag). Skill /xadm-release realinhada (aponta o release.yml, não "o CI" genérico). Mínimo para app só-script: lint sempre (piso), testes da lógica pura onde existir, sem forçar suíte em script trivial. Migração: app com ci.yml antigo de release renomeia para release.yml e adota o novo ci.yml.

0.4.1 - 2026-06-12

Alterado

  • Constituição v0.5.16 — aviso de falha do CI agora é webhook nativo da org (Forgejo 15; spec .ia/001 executada e apagada). O passo manual "Avisar falha no Telegram" (if: failure()) saiu do build-site.yml e do templates/docs.yml — a notificação vira config única na organização, sem YAML por workflow, cobrindo todos os repos. forgejo.md reescrito (BotFather → getUpdates → webhook Telegram na org com evento Action Failure). Os secrets TELEGRAM_BOT_TOKEN/TELEGRAM_CHAT_ID da org ficaram órfãos (o webhook guarda token/chat na própria config) — podem ser removidos.

Adicionado

  • Template templates/ci.yml canônico (constituição §6, "No CI (código)"): gate de análise estática + testes por stack (Java/Gradle ./gradlew check, Flutter/Dart analyze && test, Node lint && test), com base node:* para o checkout (lição do ho-scraper) e sem passo de aviso (o webhook da org cobre). Rastreado no manifesto; embutido em templates.md.
  • Constituição v0.5.15 (§2 + screenshots-manual.md): fecha a receita de screenshots Flutter (estava "em aberto"; spec .ia/002 apagada). Provada no bi-transporte (Vantroba), 9 telas com 1 comando. Correção à direção anterior: takeScreenshot não roda no desktop Linux → captura com RepaintBoundary.toImage(); alvo é o build Linux desktop (mesmo Skia do web, sem chromedriver); seed via seam de DI em memória; flag kScreenshotMode (equivalente Flutter da dica do .fade); veredito pela existência dos PNGs, não pelo exit code; custo de adoção (suporte linux/, toolchain nativo) documentado. Convenção nova: nome de PNG semântico quando há 1 imagem por tela (dre.png), senão <slug>-NN.

0.4.0 - 2026-06-12

Alterado

  • Constituição v0.5.14 (§5 + versionamento.md): o /health deixa de ser formato livre e ganha shape mínimo ({status, versao} + opcionais), pois o monitoramento (watchdog) acionou a cláusula "shape vira contrato". Receita de versão em runtime por stack (contribuição §6): Java/Micronaut (task Gradle → version.propertiesInfoSource em /info e /health + log no main; versão do @OpenAPIDefinition é contrato HTTP à parte), Node (package.json), Flutter web (tem /health, no app ou no nginx), Flutter mobile (sem HTTP → versão in-app via package_info_plus), app sem HTTP (log no startup), site estático (/versao.txt). Pertence à área Engenharia (spec 003) — fica em versionamento.md até migrar.

Adicionado

  • Página Screenshots do manual (padroes/screenshots-manual.md, constituição v0.5.13 §2): receita reproduzível para os PNGs do manual (regenerável com 1 comando; tooling em scripts/screenshots/, fora de docs/), separada por stack — web renderizada no servidor (Micronaut/Java) tem a receita provada com shot-scraper + seed.sh + shots.yml (inclui a dica do .fade/modal do Bootstrap); Flutter usa mecanismo próprio (integration_test/flutter drive), com a receita canônica em aberto (shot-scraper não serve em canvas). Ponteiro no template manual-usuario.md. Contribuição do loop §6.
  • Constituição v0.5.12 (§2/§3/§5): define o lar de artefatos não-prosa e tooling, lacuna achada nos bi-*-processador-xls. O teste é a publicabilidade (docs/ é público): referência não-prosa segura de publicar (schema de contrato, exemplo de payload, .http sem segredo) vive em docs/ no nível a que pertence (ex. docs/dev/, ao lado dos .md); ferramenta executável, insumo de build e fixture (seed, config de shot-scraper, src/.../resources) ficam fora de docs/. scripts/ reconhecido na árvore do §3 como lar de helpers de dev/ops.
  • Constituição v0.5.11 (REGRA Nº 2 / §6): no ponto de fechamento de um trabalho, junto da sugestão de commit, a IA passa a oferecer (em uma linha) avaliar se o trabalho revelou lacuna/ambiguidade/atrito no padrão — o loop §6 deixa de depender de o dev lembrar. Sincronizado em templates/claude-regras.md e no CLAUDE.md do repo.
  • Constituição v0.5.10 (§6, "No CI (código)"): o gate de build/test do app passa a exigir o conjunto análise estática + testes da stack, não só os testes — lint/estilo que só roda em check/build (checkstyle, flutter analyze) precisa falhar o PR. Comandos por stack (Java/Gradle → ./gradlew check; Flutter/Dart → analyze && test; Node → lint && test) + nota em app-novo.md. Brecha pega no bi-transporte-xls (violação de checkstyle chegou ao master). O ci.yml canônico por stack fica para a migração ao Forgejo 15 (nasce sem o passo manual do Telegram).

Corrigido

  • Template xadm-docs-skill.md ganha frontmatter (name/description): sem ele a skill /xadm-docs não é reconhecida pelo Claude Code, e cada app vinha adicionando na mão — a divergência silenciosa que o template existe para evitar (feedback do loop §6).
  • Hook checa-constituicao.sh distingue a direção da diferença de versão: base atrás (migrar), ausente (registrar) ou à frente da publicada (anomalia — central atrasado/versão registrada cedo; não migrar pra baixo). Antes, qualquer diferença mandava "migrar", o que não fazia sentido com a base à frente. Constituição v0.5.9.

0.3.2 - 2026-06-12

Alterado

  • Constituição v0.5.8 (§5): privado/ vira segmento reservado — qualquer pasta privado/ em docs/ é confidencial, não só anexos/privado/. Os guards passam a casar o padrão privado/ em vez da string fixa (exclude_docs, guard do site/ no docs.yml, --exclude do rclone no sync-apps.sh), fechando o risco de um caminho privado novo escapar em silêncio (feedback). A regra de identificadores de código em doc durável passa a citar caminho de arquivo explicitamente: fixar path só quando é contrato (URL, estrutura padrão, config canônica); onde um arquivo mora internamente se descreve pelo papel.
  • Constituição v0.5.7 (REGRA Nº 2 / §6): a IA passa a sugerir o commit de forma proativa ao fechar um trabalho e escrever a mensagem pronta para copiar (sem nunca commitar sozinha). Fixado o formato: assunto de uma linha (conventional commit) + um parágrafo curto de porquê, sem lista de arquivo por arquivo. Sincronizado em templates/claude-regras.md e no CLAUDE.md do repo.

Adicionado

  • Constituição v0.5.6 (§6): manifesto de templates — o site publica padroes/manifesto.json com o hash e a versão mudou_em de cada artefato copiado para os apps (workflow docs.yml, mkdocs.yml, app.json, hook e skills), e os arquivos crus em padroes/raw/<arquivo>. A /xadm-docs passa a listar mecanicamente quais templates do app estão defasados (mudou_em > versão-base) e re-baixá-los, em vez de inferir da leitura — fechando o modo de falha em que uma mudança de template passou despercebida (ho-scraper). scripts/gera-manifesto.py (--check no CI, --update ao mexer num template); o --check falha o build se um template mudou sem o manifesto refletir, e o --update cobra o bump da constituição.

0.3.1 - 2026-06-11

Adicionado

  • Constituição v0.5.5 (feedback do bi-transporte-xls): princípio §1.9 "Duas fontes da verdade: o código e docs/" — artefato de trabalho (spec, plano, prompt) é andaime: destila para docs/ ao concluir e é apagado ("feature pronta" inclui poder apagá-lo sem perda); CLAUDE.md é roteador, não acervo (§6: regras + versão-base + ponteiros; conhecimento durável vive em docs/); convenção no §5 sobre identificadores de código em doc durável (citar nome concreto só quando ele é a interface; mecânica interna se descreve pelo papel).

0.3.0 - 2026-06-11

Adicionado

  • valida-frontmatter.py cruza o cliente: do frontmatter com o app.json: app de cliente exige o campo igual em todo doc (pega ausência e typo); app da X-Adm não leva o campo. Sem app.json, não checa (feedback do BI Transporte Vantroba).
  • Checklist de app novo: site/ no .gitignore (build local gera a pasta; site gerado nunca é commitado) e conferência da constituicao-versao.txt antes E depois de copiar os templates (release da constituição no meio de uma adoção já passou despercebido).
  • Versionamento: formato do payload do /health declarado livre — o contrato é 200 quando vivo + versão legível (o version.json do build Flutter satisfaz); shape só vira contrato se houver monitoramento, e mudará no padrão primeiro.
  • Aviso de falha do CI no Telegram: passo canônico if: failure() no final de cada job (mensagem com repo, workflow/job, ref e link da run), com secrets TELEGRAM_BOT_TOKEN/TELEGRAM_CHAT_ID herdados da organização xadm. Incluído no templates/docs.yml e no workflow do site central; passo a passo (BotFather, chat_id, secrets) em infraestrutura/forgejo.md. Sem os secrets, o passo só loga — não falha.

0.2.3 - 2026-06-11

Adicionado

  • Constituição v0.5.4 (§3 e §5): regra "docs/ é público" (nada de dado real de cliente, credencial ou massa de dados solta — brecha apontada pelo bi-transporte-xls) e pastas padrão docs/anexos/ (anexo público deliberado) e docs/anexos/privado/ (confidencial, ex. planilha-base com dados reais — versionada no Git, nunca publicada), cada uma com README obrigatório (templates canônicos novos).
  • Três guardas independentes para anexos/privado/: exclude_docs no mkdocs.yml canônico (e no do site central), falha no CI do app se a pasta aparecer no site/ (templates/docs.yml) e --exclude no rclone do sync-apps.sh — o portal recusa servir o caminho mesmo publicado por engano.
  • valida-frontmatter.py bloqueia massa de dados (.xlsx, .csv, .sql, .zip...) em docs/ fora de anexos/; .docx do pré-projeto continua liberado.

0.2.2 - 2026-06-11

Corrigido

  • Constituição v0.5.3 (§3, nota de legado): guias/ migra por conteúdo, não por rename fixo — manual de usuário → manual/, runbook técnico → operacao/. A pasta legada abrigava os dois níveis; o mapa 1:1 anterior mandava runbook para manual/ errado (brecha apontada pelo ho-scraper). Mesmo ajuste no templates/xadm-docs-skill.md.

Adicionado

  • Padrões: seção "Ambiente local (Linux/Ubuntu)" em publicar-docs.md — MkDocs global via pipx (sem venv manual, respeitando o PEP 668 do Ubuntu 24.04+), com as versões pinadas da toolchain; link no checklist de app novo.

0.2.1 - 2026-06-11

Corrigido

  • CI do site: o job de validação quebrava no checkout por falta de node no container (python:3.12-slim); o workflow agora usa node:22-bookworm-slim com git e Python instalados antes do checkout — a falha impedia o próprio deploy (a v0.2.0 não tinha chegado a subir).

0.2.0 - 2026-06-11

Adicionado

  • Constituição v0.4.0: modelo de seis níveis com nível Operação (runbooks técnicos em docs/operacao/, tipo: operacao) e nível Dev (API reference gerada + docs/dev/ opcional para doc escrita à mão).
  • Template runbook.md (O que é / Quando usar / Pré-requisitos / Passos / Verificação / Reversão), embutido na página de templates.
  • Validação do contrato de release no CI do site (valida-release.py no build-site.yml; push de tag v* confere tag × VERSION).
  • Constituição v0.4.1, governança: regra "IA não decide sozinha" — todo repo que usa Claude Code abre o CLAUDE.md com a regra de confirmar com o usuário antes de implementar quando houver ambiguidade ou mais de um caminho possível.
  • Constituição v0.5.1, governança: regra "IA não faz commit/push sozinha" (única exceção: a skill /xadm-release) e bloco canônico templates/claude-regras.md com as duas regras de IA, pronto para colar no CLAUDE.md de cada repo.
  • Constituição v0.5.0, governança: rastreio de versão-base — o app registra em constituicao: (docs/app.json) a versão que a doc segue; o site publica a vigente em /padroes/constituicao-versao.txt e o fonte cru em /padroes/constituicao.md; skill canônica /xadm-docs (compara, avalia e migra com aprovação) e hook SessionStart (checa-constituicao.sh) que avisa ao abrir o Claude Code no repo.
  • Rodapé do site passa a exibir a versão vigente da constituição e a versão do próprio site + copyright X-Adm (hook scripts/copyright-versao.py, que lê o frontmatter da constituição e o arquivo VERSION no build).
  • Página IA e Claude Code (padroes/ia.md): o que é o Claude Code, as regras de governança de IA, o catálogo de skills da plataforma (/xadm-release, /xadm-docs), o hook de sessão e como adotar num repo; constituição v0.5.2 referencia a página no §6.

Alterado

  • Nomenclatura definitiva das pastas de documentação: design/projeto/, rd/decisoes/, guias/manual/ (tipos projeto | decisao | dev | operacao | manual); o validador segue aceitando os nomes antigos até a migração oportunista dos repos.
  • Templates renomeados: doc-projeto.md, decisao.md, manual-usuario.md.
  • Skill de release renomeada de /release para /xadm-release (template xadm-release-skill.md e a cópia instalada neste repo).

0.1.0 - 2026-06-11

Adicionado

  • Site central de documentação (MkDocs Material, pt-BR, identidade visual X-Adm) com constituição, glossário da plataforma e docs de infraestrutura.
  • Constituição da documentação v0.3.6 (níveis, frontmatter, convenções, governança com loop de feedback dos apps).
  • Templates canônicos: design doc, RD, guia de usuário, mkdocs.yml, workflow docs.yml, app.json e skill /release.
  • Pipeline descentralizado: apps publicam no bucket docs-sites e o site sincroniza (~90s) com log de mudanças por app.
  • Listagem automática de aplicações e API references via app.json + index.json.
  • Validadores valida-frontmatter.py e valida-release.py, publicados no site público para consumo pelos CIs dos apps.
  • Checklist de app novo e página de versionamento/release.
  • Health check da imagem e carimbos de versão (/versao.txt) e commit (/commit.txt).