Ir para o conteúdo

Estabilidade & suporte

O que você vai encontrar

O contrato de estabilidade rumo ao 1.0 (S10) e o contrato do subset do Modo C (S11): o que é público e estável, o que muda, quais browsers são suportados e onde está o baseline de acessibilidade.

Versionamento (rumo a 1.0)

tempestweb é pré-1.0 (0.x). Enquanto isso:

  • Superfície pública = o que é importável de tempestweb e seus subpacotes documentados (tempestweb.server, tempestweb.native, tempestweb.transpile, tempestweb.html, tempestweb.pwa, tempestweb.cli) + o wire-contract (docs/contract.md). Nomes com _ são privados.
  • Compatibilidade: minor 0.x pode conter mudanças de comportamento documentadas no CHANGELOG. Fixe a versão em produção.
  • Depreciação (a partir do 1.0): um recurso a ser removido ganha um aviso por pelo menos um minor antes de sair; removidos só em major.

Matriz de browsers

Browser Modo A (WASM) Modo B (servidor) Modo C (transpile)
Chrome/Edge ≥ 111 ✅ ✅ ✅
Firefox ≥ 110 ✅ ✅ ✅
Safari ≥ 16.4 ✅¹ ✅ ✅

Requisitos: ES modules + fetch + WebSocket/EventSource. PWA instalável precisa de HTTPS; push no iOS exige o app instalado (Safari ≥ 16.4). ¹O boot do Pyodide (Modo A) é mais pesado no Safari/mobile — prefira B ou C para first-paint/SEO.

Acessibilidade

O cliente emite HTML semântico com roles/aria a partir de Widget.semantics (aria-label/role/aria-description), tabindex por focus_order, e usa controles nativos (<input>/<button>) onde possível.

O baseline é medido, não declarado. O job a11y do CI roda axe-core sobre o DOM que o renderizador de verdade constrói, para cenas geradas dos apps que este repo entrega (tests/conformance/_a11y_scenes.py → scripts/a11y-gate.mjs), e trava o merge em violação serious ou critical:

São dois jobs, porque as regras se dividem por aquilo de que precisam:

Job Onde roda O que mede
a11y jsdom estrutura: controle sem nome acessível, imagem sem alt, role inválido, interativo aninhado, rótulo sem campo, id duplicado
contrast Chromium real color-contrast sobre o DOM pintado, nas cenas em light e dark

Contraste precisa de caixa com layout para amostrar cor, e o jsdom não produz uma — por isso ele é a única regra que o job a11y desliga, e por isso o job contrast existe. Os dois auditam as mesmas cenas geradas, então não podem divergir.

As cenas são geradas, não escritas à mão: a galeria de componentes do Modo C, o painel de controles, uma lista com campo de texto, um formulário, uma casca de navegação com gaveta e uma tela de imagens. Auditar markup escrito à mão provaria que o exemplo do teste é acessível, não que o renderizador é.

A cobertura se mede por tipo de widget e por componente, e o segundo eixo tinha um buraco: nove cenas e nenhuma usava os campos que são deste repo (TextField/EmailField/PasswordField e os dois formulários). A cena login-form parece usar e não usa — ela monta EmailInput/PasswordInput do core dentro de um FormField, que o renderizador nomeia. Resultado: o PasswordField entregou um controle anônimo (label, crítico) com o gate verde até a 0.113.0. login_demo fecha esse eixo.

O tema entra na geração da cena, não no DOM

A cena dark é construída sob o tema dark (tests/fixtures/a11y_scenes_dark.json), não obtida trocando um atributo na árvore já renderizada. O que o core resolve — a cor de um Text, a superfície de um Card — viaja como style inline na IR, então uma árvore construída em light sob a folha dark é uma mistura que não existe em app nenhum. Medida assim, ela acusou 9 violações; construída por tema, 2 — e as 2 eram reais.

Regra que só pode ser afrouxada por escrito: uma regra do axe que não se aplica a uma cena entra em KNOWN_EXCEPTIONS com o motivo (hoje: as regras de documento inteiro — landmark-one-main, page-has-heading-one, region). O gate de contraste tem a sua própria lista, chaveada pelo par de cores em vez de pela regra, porque é o par que precisa mudar; as entradas de hoje pertencem todas ao tempest-core, cuja paleta este repo pina e não edita. Os dois gates relatam exceção que parou de disparar, para lista de exceção não apodrecer em silêncio. Silenciar sem motivo escrito é o que transformou "baseline de a11y" em declaração vazia antes.

O wire-contract é congelado

O wire-contract (docs/contract.md) é parte da superfície estável, então ele tem versão própria — independente da versão do pacote — em tempestweb.contract:

from tempestweb.contract import WIRE_CONTRACT_VERSION, WIRE_SHAPE_DIGEST

As golden fixtures já travavam drift acidental, mas são regeneráveis do core: elas não distinguem "regenerei porque o core mudou" de "mudei o contrato". O WIRE_SHAPE_DIGEST distingue — ele é o hash da forma do fio (cada chave e seu tipo, nunca o valor), então:

Mudança Digest Versão O que mais
fixture regenerada com valores novos igual igual nada
chave opcional nova, kind de envelope novo, type de evento novo muda igual entrada no CHANGELOG
chave renomeada/removida/retipada, semântica de patch alterada muda bump nota de migração

tests/unit/test_wire_contract_freeze.py reprova a mudança de forma e diz, na mensagem, qual das duas escolhas o autor deve. Cliente de terceiro pinam WIRE_CONTRACT_VERSION e sabem com o que estão falando.

Contrato do subset do Modo C (S11)

O transpilador aceita um subset tipado de Python — estável e fail-loud (arquivo:linha para o que estiver fora). Ver a lista completa no guia do Modo C.

Dentro (estável): dataclasses (com herança/métodos/kwargs), view() + closures de handler, aritmética completa, comparação encadeada, comprehensions (lista/dict, com alvo em tupla), literais, slices, f-strings formatadas, builtins comuns, métodos stdlib de string/list/dict, if/for/while/break/ continue/try-except-finally/with/raise/assert, unpacking, atribuição encadeada, navegação/i18n/tema/animação/validators e todas as capacidades native/.

Fora (por decisão): global, yield/geradores, del, walrus (:=), raise ... from, unpacking com estrela, decorators arbitrários (só @dataclass), e a maior parte de tempest_core.components (composição Python que expande via build() — use Modos A/B, ou primitivos/HStack/VStack no C). A decisão de portar os components (camada de resolvers em JS) segue no roadmap — S11.

Portabilidade A/B/C

Um view() no subset roda idêntico nos três modos. O build --mode transpile valida isso renderizando pelo core real — uma API só-do-Modo-C quebraria o build.

Recap

  • Pré-1.0: superfície pública documentada + wire-contract; fixe a versão.
  • Browsers modernos (Chrome/Edge/Firefox/Safari recentes) nos três modos.
  • a11y por semantics/roles, medida por dois gates que travam o merge: a11y (estrutura, jsdom) e contrast (color-contrast pintado, Chromium, light + dark).
  • Subset do Modo C é um contrato estável e fail-loud; components ficam em A/B.