tactual-mcp

Analisador de custo de navegação por leitores de tela que mede o esforço real de navegação para usuários de tecnologia assistiva, construindo um grafo ponderado a partir de snapshots de acessibilidade do Playwright e pontuando cada destino sob perfis reais de tecnologia assistiva (NVDA, JAWS, VoiceOver, TalkBack, mobile genérico).

Documentação

Tactual

Tactual logo

Analisador de custo de navegação para leitores de tela. Mede quantos toques de teclado um usuário de leitor de tela precisa para descobrir, alcançar e operar cada alvo interativo na sua página — sob um perfil de tecnologia assistiva (AT) específico (NVDA, JAWS, VoiceOver).

O que ele faz

Ferramentas de acessibilidade existentes verificam conformidade — o ARIA está correto? A taxa de contraste é suficiente?

O Tactual mede o custo de navegação — quantas ações um usuário de leitor de tela precisa para chegar ao botão de checkout? O que acontece se ele passar do ponto? Ele consegue sequer descobrir que o botão existe? O menu realmente abre com Enter, ou apenas com clique? O foco vai para o primeiro item do menu ou fica preso no gatilho?

Como funciona:

  • Captura snapshots de acessibilidade do Playwright + simulação de anúncios do leitor de tela
  • Opcionalmente explora ramos ocultos (menus, diálogos, abas, disclosures) e os testa com eventos reais de teclado, incluindo contratos de widgets no estilo APG e fluxos de erro de formulário
  • Constrói um grafo de navegação com pontos de entrada (landmarks, títulos, Tab linear) e pontua cada alvo
  • Opcionalmente valida caminhos previstos contra @guidepup/virtual-screen-reader para calibração

O Tactual é uma ferramenta de desenvolvedor para analisar seus próprios sites e ambientes de staging. Execute-o localmente, em CI, ou via servidor MCP no seu editor. Não é um serviço público de varredura.

Como ele se encaixa

O Tactual complementa scanners de conformidade como axe-core, Lighthouse e Pa11y. Essas ferramentas ainda são a primeira passagem correta para ampla cobertura de regras WCAG e ARIA. O Tactual visa a próxima pergunta: depois que uma página tem marcação válida, quão caro é para um usuário de AT descobrir, alcançar e operar os alvos importantes?

Use o Tactual para triagem de custo de navegação com leitor de tela, rastreamento de caminhos, evidências medidas de teclado/widget, diffs antes/depois, priorização em CI e fluxos de trabalho MCP onde um agente precisa de achados compactos com seletores de origem e candidatos a correção. Use leitores de tela reais e testes manuais para validação final de jornadas críticas, fluxos sensíveis a tempo, configurações de navegador/AT e padrões de implementação que intencionalmente diferem de um exemplo APG comum.

Caminho rápido para agentes: este README é uma visão geral do produto mais referência. Agentes devem começar com docs/AGENT-RECIPES.md para padrões de tarefas e docs/MCP-TOOLS.md para esquemas MCP completos, e depois voltar aqui apenas para contexto do produto, notas de instalação e exemplos de superfície de lançamento.

Instalação

Requer Node.js 20 ou posterior.

npm install tactual

O Tactual instala o Playwright como dependência de runtime para que comandos avulsos de npx tactual@latest ... funcionem sem instalar o Playwright separadamente no cache do npx. O SDK MCP também acompanha como dependência de runtime, então tactual-mcp funciona a partir de um pacote tactual instalado sem uma instalação separada do SDK.

Início rápido

CLI

# Analyze a URL (default profile: generic-mobile-web-sr-v0)
npx tactual analyze-url https://example.com

# Analyze with a specific AT profile
npx tactual analyze-url https://example.com --profile voiceover-ios-v0

# Explore hidden UI (menus, tabs, dialogs, disclosures)
npx tactual analyze-url https://example.com --explore

# Use a scoring preset for your use case
npx tactual analyze-url https://shop.com --preset ecommerce-checkout
npx tactual analyze-url https://docs.example.com --preset docs-site

# Output as JSON, Markdown, or SARIF
npx tactual analyze-url https://example.com --format json --output report.json
npx tactual analyze-url https://example.com --format sarif --output report.sarif

# Compare two analysis runs
npx tactual diff-results baseline.json candidate.json
npx tactual diff-results baseline.json candidate.json --format json

# Print what NVDA would say as you Tab through the page
npx tactual transcript https://example.com
npx tactual transcript https://example.com --at voiceover

# List available AT profiles and scoring presets
npx tactual profiles
npx tactual presets

# Run benchmark suites
npx tactual benchmark
npx tactual benchmark --suite all

Benchmark fixtures ship with the npm package, so the benchmark command works from a fresh install and does not require cloning the repository fixtures into your current directory.

# Validate predicted paths against a virtual screen reader (reachability + step count)
# Requires optional deps, installed by default with tactual
npx tactual validate-url https://example.com --max-targets 10 --strategy semantic

# Initialize a tactual.json config file
npx tactual init

# Analyze a bot-protected site with stealth + real Chrome
npx tactual analyze-url https://www.npmjs.com/ --stealth --channel chrome

# Deep keyboard probing including revealed widgets and form-error flows
npx tactual analyze-url https://docs.example.com --probe --explore --probe-mode deep

# Focus probing on one opened branch, such as a dialog trigger
npx tactual analyze-url https://app.example.com/settings \
  --probe \
  --entry-selector "[aria-controls='profile-dialog']" \
  --probe-strategy modal-return-focus

# Analyze + inline virtual-SR validation in one command (predicted vs validated steps)
npx tactual analyze-url https://example.com --validate --validate-max-targets 10

A saída do console inclui uma linha de caminho compactada para cada achado mostrando como um usuário de leitor de tela o alcança:

  ██████░░ 70  link:reference structural
               D:47 R:71 O:100 Rec:100
               getByRole('link', { name: 'Reference' })
               ↪ Tab ×2 "v19.2" → K "Learn" → Tab "Reference"
               → Target is not efficiently reachable via heading or landmark navigation

Onde Tab = nextItem, H = nextHeading, ; = nextLandmark, K = nextLink, B = nextButton, Enter = ativar. Etapas consecutivas com a mesma ação são colapsadas (Tab ×2).

Da Auditoria à Correção

Para trabalho de acessibilidade em um aplicativo local ou ambiente de preview, o Tactual fornece evidências para mudanças pequenas e revisáveis:

  • selector, penalties, suggestedFixes e resumos de evidência em cada achado
  • issueGroups agrupados e candidatos a correção na saída resumida
  • analyze_pages.site.repeatedNavigation para custo de navegação repetido entre rotas
  • diff-results / diff_results para verificação antes e depois

Comece com triagem ampla, depois aprofunde uma rota antes de mudar o código:

# Site-level triage. Redirect JSON for tool consumption.
npx tactual analyze-pages \
  https://app.example.com/ \
  https://app.example.com/docs \
  https://app.example.com/settings \
  --profile nvda-desktop-v0 \
  --format json > tactual-site.json

# Deepen one route and produce a reviewable markdown report.
npx tactual analyze-url https://app.example.com/docs \
  --profile nvda-desktop-v0 \
  --explore --probe --probe-mode standard \
  --format markdown --output tactual-report.md

# When one branch is the target, open it first and spend probe budget there.
npx tactual analyze-url https://app.example.com/docs \
  --profile nvda-desktop-v0 \
  --probe \
  --entry-selector "[aria-controls='search-panel']" \
  --probe-selector "#search-panel" \
  --probe-strategy composite-widget \
  --format markdown --output tactual-search-panel.md

# Save a baseline before editing, then verify the patch.
npx tactual analyze-url https://app.example.com/docs --explore --probe --format json --output baseline.json
# Edit one root cause in the local repo, rebuild/restart the preview, then re-run:
npx tactual analyze-url https://app.example.com/docs --explore --probe --format json --output candidate.json
npx tactual diff-results baseline.json candidate.json

Use a seção de candidatos como ponto de partida para causas raiz repetidas, como um componente compartilhado, padrão de navegação ou contrato de widget. Confirme o componente de origem e inclua a rota, comando, evidência do achado, impacto no usuário, mudança de código e verificação em qualquer formato de issue ou PR que o projeto espera. A mudança na pontuação é evidência de apoio útil, mas a mudança deve liderar com o comportamento de acessibilidade que foi alterado.

Clientes MCP podem consumir a mesma saída compacta e manter o ciclo de revisão fundamentado em rotas, seletores, evidências, mudanças de origem e verificação antes/depois.

API de Biblioteca

import { analyze, getProfile } from "tactual";
import { captureState } from "tactual/playwright";
import { chromium } from "playwright";

const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto("https://example.com");

const state = await captureState(page);
await browser.close();

const profile = getProfile("generic-mobile-web-sr-v0");
const result = analyze([state], profile);

for (const finding of result.findings) {
  console.log(finding.targetId, finding.scores.overall, finding.severity);
}

Simulador de anúncios de leitor de tela — prevê o que NVDA, JAWS ou VoiceOver anunciariam para cada alvo, com informações de estado (marcado, expandido, selecionado, modal, valor, obrigatório, inválido, etc.):

import {
  simulateScreenReader,
  buildAnnouncement,
  buildMultiATAnnouncement,
  buildTranscript,
} from "tactual/playwright";

const report = await simulateScreenReader(page, state.targets);

for (const a of report.formFields) {
  console.log(a.announcement);
  // → "Subscribe, check box, checked"
  // → "Country, combo box, collapsed"
  // → "Email, edit, invalid entry, required, you must use a work address"
}

// Compare across screen readers
const tx = state.targets[5];
buildAnnouncement(tx, "nvda"); // → "Country, combo box, collapsed"
buildAnnouncement(tx, "voiceover"); // → "Country, popup button"

// All three at once
buildMultiATAnnouncement(tx);
// → { nvda: "...", jaws: "...", voiceover: "..." }

// Linear navigation transcript — what an SR user hears Tabbing through
const transcript = buildTranscript(state.targets, "nvda");
// → [{ step: 1, kind: "landmark", announcement: "Main, main landmark" }, ...]

// Multi-target navigation modes (linear, by-heading, by-landmark, by-form-control)
import { buildNavigationTranscript } from "tactual/playwright";

// Heading-only navigation (NVDA: H key)
const headings = buildNavigationTranscript(state.targets, { mode: "by-heading" });

// Navigate from one element to another
const path = buildNavigationTranscript(state.targets, {
  from: "link:before-main",
  to: "heading:welcome",
  mode: "linear",
});

// Demoted landmarks (in DOM but stripped by HTML rules, e.g. <header> in <section>)
for (const d of report.demotedLandmarks) {
  console.warn(d.demotionReason);
}

APIs de validação e calibração — compara a saída do modelo contra execuções de validação de SR virtual ou conjuntos de dados de observação humana:

import { validateFindingsInJsdom } from "tactual/validation";
import { runCalibration, formatCalibrationReport } from "tactual/calibration";

// Given a JSDOM instance, PageState, AnalysisResult, and calibration dataset:
const validation = await validateFindingsInJsdom(dom, state, result.findings, {
  maxTargets: 10,
  strategy: "semantic",
});

const calibration = runCalibration(dataset, new Map([[state.url, result]]));
console.log(validation, formatCalibrationReport(calibration));

Ou pela CLI:

npx tactual transcript https://example.com --at voiceover
npx tactual calibration-report my-calibration.json --analysis example-nvda.json

O simulador é previsão heurística, não saída real de leitor de tela. O simulador em si é rápido (JavaScript puro sobre alvos capturados — sub-segundo uma vez que os alvos estão em memória), mas uma execução completa de analyze-url inclui inicialização do navegador + captura de página + pontuação e leva segundos em páginas pequenas, mais tempo com --probe (~30s+) e --explore (~1–5 min em SPAs complexos). A análise roda em navegador headless por padrão, então nada aparece enquanto você trabalha. (Use --no-headless ou --channel chrome --stealth para sites visíveis/protegidos contra bots.)

Qualidade de dados. Calibrado contra asserções em nível de token do projeto W3C ARIA-AT: 77/77 asserções de token de papel/nome/estado passam a 100% nos três ATs (NVDA, JAWS, VoiceOver), cobrindo formulação de papel/nome/estado para 36 padrões de alvo único (botão, botão de alternância, todas as variantes de botão de menu, disclosure, accordion, checkbox/estado triplo, switch, sliders, diálogo, alerta, links, abas, comboboxes, radiogroups, spin button, menubar) mais 4 cenários de landmark com múltiplos alvos. Execute npm run calibrate após npm run build para verificar contra as asserções upstream mais recentes. Isso é calibração de simulador, não prova de fidelidade completa de leitor de tela entre modos de navegação, configurações de verbosidade, tempo ou cada variante válida de widget. Overrides específicos de AT fora do conjunto calibrado são rotulados com confiança ALTA/MÉDIA/BAIXA na origem.

Servidor MCP

O Tactual inclui um servidor MCP para consumo por agentes de IA:

# Start the MCP server (stdio transport — default)
npx tactual-mcp

# Start with HTTP transport (for hosted platforms, remote clients)
npx tactual-mcp --http              # listens on http://127.0.0.1:8787/mcp
npx tactual-mcp --http --port=3000  # custom port (or set PORT env var)
npx tactual-mcp --http --port 3000  # space-separated form is also supported
npx tactual-mcp --http --host=0.0.0.0  # bind to all interfaces (default: 127.0.0.1)

Para implantações MCP voltadas à rede, coloque o transporte HTTP atrás de um proxy TLS autenticado e mantenha-o restrito a clientes confiáveis. Veja SECURITY.md para a lista de verificação hospedada e modelo de ameaça.

Ferramentas MCP disponíveis:

FerramentaDescrição
analyze_urlAnalisa uma página para custo de navegação SR (padrão SARIF). Suporta exploração opcional, sondas de teclado/widget/formulário, sondagem direcionada/por objetivo, stealth/channel para sites protegidos contra bots e filtragem.
trace_pathCaminho de navegação passo a passo até um alvo com anúncios SR modelados.
validate_urlValida caminhos previstos contra @guidepup/virtual-screen-reader. Retorna alcançável + precisão média por estratégia (linear/semântica). Fecha o ciclo previsto-vs-validado.
calibration_reportExecuta conjuntos de dados de calibração observados contra JSON de análise completa salvo e retorna sinais de pontuação estruturados para fluxos de ajuste/revisão.
list_profilesLista perfis de AT disponíveis.
diff_resultsCompara dois resultados de análise — melhorias, regressões, mudanças de severidade.
suggest_remediationsSugestões de correção ranqueadas por impacto.
save_authAutentica e salva estado de sessão para analisar conteúdo protegido.
analyze_pagesTriagem de site com múltiplas páginas com estatísticas agregadas e grupos de custo de navegação repetidos entre páginas.

Referência completa de parâmetros: docs/MCP-TOOLS.md

Configuração por ferramenta de IA

Primeiro instale os pacotes necessários no seu projeto:

npm install tactual

Claude Code — adicione a .mcp.json na raiz do seu projeto:

{
  "mcpServers": {
    "tactual": {
      "type": "stdio",
      "command": "npx",
      "args": ["tactual-mcp"]
    }
  }
}

GitHub Copilot — adicione a .copilot/mcp.json ou ~/.copilot/mcp-config.json:

{
  "mcpServers": {
    "tactual": {
      "type": "stdio",
      "command": "npx",
      "args": ["tactual-mcp"]
    }
  }
}

Cursor / Windsurf / Cline — mesmo formato na configuração MCP do seu editor:

{
  "mcpServers": {
    "tactual": {
      "command": "npx",
      "args": ["tactual-mcp"]
    }
  }
}

Direto (instalação global) — se preferir não usar npx:

npm install -g tactual
tactual-mcp  # starts the MCP server on stdio

GitHub Actions

Use a action composta do GitHub Actions Marketplace:

jobs:
  a11y:
    runs-on: ubuntu-latest
    permissions:
      security-events: write # for SARIF upload
      pull-requests: write # for comment-on-pr
    steps:
      - name: Analyze accessibility
        uses: tactual-dev/tactual@v0.5.0
        with:
          url: https://your-app.com
          profile: nvda-desktop-v0
          explore: "true"
          probe: "true"
          probe-mode: standard
          fail-below: "70"
          comment-on-pr: "true"

A action instala o Tactual e os binários do navegador Chromium, executa a análise, envia SARIF para o GitHub Code Scanning e falha o build se a pontuação média estiver abaixo do limite. Defina comment-on-pr: "true" para postar um comentário resumido em pull requests (atualiza em re-execução). Saídas average-score e result-file para etapas downstream. A versão da action acompanha a versão do Tactual — aumente a linha uses: para receber patches.

Os padrões são conservadores: probe está desligado a menos que habilitado porque envia eventos reais de teclado, e verificações de ícones com cores forçadas rodam apenas para perfis que declaram visualModes como nvda-desktop-v0 e jaws-desktop-v0.

Ou use a CLI diretamente para mais controle:

- name: Install Tactual
  run: npm install tactual

- name: Install browsers
  run: npx playwright install chromium --with-deps

- name: Run accessibility analysis
  run: npx tactual analyze-url https://your-app.com --format sarif --output results.sarif --threshold 70

- name: Upload SARIF
  uses: github/codeql-action/upload-sarif@v3
  with:
    sarif_file: results.sarif

Portão de regressão (falha de CI em pior-que-baseline)

Combine --baseline com --fail-on-regression para transformar o Tactual em um portão estrito de CI: salve um baseline de um build conhecidamente bom, depois falhe verificações de PR sempre que uma mudança regredir N+ achados vs o baseline. O comando diff-results também pode ser executado separadamente para relatórios legíveis de antes/depois.

# One-time: snapshot main as the baseline
- name: Snapshot baseline
  if: github.ref == 'refs/heads/main'
  run: |
    npx tactual analyze-url https://preview.your-app.com \
      --format json --output tactual-baseline.json

- name: Upload baseline
  if: github.ref == 'refs/heads/main'
  uses: actions/upload-artifact@v4
  with:
    name: tactual-baseline
    path: tactual-baseline.json

# On PRs: compare against the baseline, fail on regressions
- name: Fetch baseline
  uses: actions/download-artifact@v4
  with:
    name: tactual-baseline

- name: Analyze + gate on regressions
  run: |
    npx tactual analyze-url https://pr-preview-${{ github.event.number }}.your-app.com \
      --format sarif --output results.sarif \
      --baseline tactual-baseline.json \
      --fail-on-regression 3     # fail if 3+ findings regressed

Ou via action:

- uses: tactual-dev/tactual@v0.5.0
  with:
    url: https://pr-preview.your-app.com
    baseline: tactual-baseline.json
    fail-on-regression: "3"

A action espelha a superfície CLI de analyze-url para entradas de análise, e um teste de contrato CI-para-CLI mantém esses campos alinhados. Alguns controles de fluxo de trabalho são orquestração da Action em vez de flags diretas da CLI: fail-below envolve a CLI --threshold, comment-on-pr controla a etapa de comentário em PR, e o upload de SARIF é tratado pelo fluxo de trabalho. As entradas comuns que você definirá incluem profile, explore, explore-depth, explore-budget, explore-timeout, probe, probe-mode, probe-strategy, scope-selector, probe-selector, entry-selector, goal-target, goal-pattern, stealth, channel, wait-for-selector, exclude, exclude-selector, focus, min-severity, max-findings, baseline, fail-on-regression, fail-below, validate, storage-state, summary-only. O padrão de invocação direta da CLI acima ainda é o caminho recomendado quando você quer uma versão diferente do Tactual daquela fixada pela action.

SuperfícieConvenção de nomenclaturaExemplo
CLIflags kebab-case--probe-strategy modal-return-focus
Opções MCP e de bibliotecacampos camelCaseprobeStrategy: "modal-return-focus"
GitHub Actioninputs kebab-caseprobe-strategy: modal-return-focus

Configuração

Flags de CLI

Options:
  -p, --profile <id>              AT profile (default: generic-mobile-web-sr-v0)
  -f, --format <format>           json | markdown | console | sarif (default: console)
  -o, --output <path>             Write to file instead of stdout
  -d, --device <name>             Playwright device emulation
  -e, --explore                   Explore hidden branches
  --explore-depth <n>             Max exploration depth (default: 3)
  --explore-budget <n>            Max exploration actions (default: 50)
  --explore-timeout <ms>          Total exploration timeout; includes probe time when combined with --probe (default: 60000)
  --explore-max-targets <n>       Max accumulated targets before stopping (default: 2000)
  --allow-action <patterns...>    Allow exploring controls matching these patterns (overrides safety)
  --exclude <patterns...>         Exclude targets by name/role glob
  --exclude-selector <css...>     Exclude elements by CSS selector
  --scope-selector <css...>       Capture, score, and probe only these subtrees
  --focus <landmarks...>          Only analyze within these landmarks
  --suppress <codes...>           Suppress diagnostic codes
  --top <n>                       Show only worst N findings
  --min-severity <level>          Minimum severity to report
  --threshold <n>                 Exit non-zero if avg score < N
  --preset <name>                 Scoring preset (ecommerce-checkout, docs-site, dashboard, form-heavy)
  --config <path>                 Path to tactual.json
  --no-headless                   Headed browser (for bot-blocked sites)
  --channel <name>                Browser channel: chrome, chrome-beta, msedge (uses installed browser; bypasses most bot detection)
  --stealth                       Anti-detection defaults: realistic UA, override navigator.webdriver, spoof plugins/languages
  --user-agent <ua>               Override User-Agent string
  --timeout <ms>                  Page load timeout (default: 30000)
  --probe                         Opt-in runtime keyboard probes for interactive targets
                                    (focus, activation, Escape, Tab).
                                    Also probes menu, dialog, tab, disclosure, combobox/listbox,
                                    and form-error patterns.
                                    When combined with --explore, probes revealed-state targets too
                                    (menu items, dialog bodies, expanded widgets).
  --probe-budget <n>              Override generic-probe budget (default: per --probe-mode)
  --probe-mode <mode>             fast | standard (default) | deep.
                                    fast=5 generic/5 menu/3 modal/5 widget;
                                    standard=20/20/10/20; deep=50/40/20/40.
                                    Budget is shared across initial + all revealed states.
  --probe-selector <css...>       Probe only these subtrees without changing capture/scoring
  --entry-selector <css>          Activate this trigger before capture/probe
  --goal-target <target>          Exact-ish target id/name/role/kind/selector hint
  --goal-pattern <pattern>        Glob target id/name/role/kind/selector hint
  --probe-strategy <strategy>     all | overlay | composite-widget | form |
                                    navigation | modal-return-focus | menu-pattern
  --validate                      Run the virtual screen reader over the captured DOM and include
                                    a predicted-vs-validated step comparison in the output.
                                    Requires optional deps: jsdom + @guidepup/virtual-screen-reader.
                                    Installed by default unless optional deps were omitted.
  --validate-max-targets <n>      Max findings to validate (default: 10)
  --validate-strategy <mode>      Virtual-SR nav strategy: linear | semantic (default: semantic)
  --check-visibility              Force per-icon contrast check across the profile's visualModes
  --no-check-visibility           Disable per-icon contrast check even if profile declares modes
  --detect-routes                 Record SPA route changes during analysis
  --descend-frames                Include iframe accessibility targets; Chromium can recover many cross-origin OOPIFs via CDP
  --auto-scroll                   Scroll before capture to surface lazy/infinite-scroll content
  --dismiss-banners               Best-effort dismissal of safe cookie/consent banners
  --probe-hover                   Hover likely triggers to expose hover-only popup content
  --walk-tab-order                Record Tab traversal to detect focus-order/focus-trap issues
  --diff-viewports                Compare desktop and mobile captures for hidden content
  --wait-for-selector <css>       Wait for selector before capturing (for SPAs)
  --wait-time <ms>                Additional wait after page load
  --storage-state <path>          Playwright storageState JSON for authenticated pages
  --also-json <path>              Also write JSON to this path (single analysis run for CI)
  --summary-only                  Return only summary stats, no individual findings
  -q, --quiet                     Suppress info diagnostics

tactual.json

Crie com tactual init ou manualmente:

{
  "preset": "ecommerce-checkout",
  "profile": "voiceover-ios-v0",
  "exclude": ["easter*", "admin*", "debug*"],
  "excludeSelectors": ["#easter-egg", ".admin-only", ".third-party-widget"],
  "scopeSelectors": ["main"],
  "probeSelectors": [".checkout-dialog"],
  "probeStrategy": "modal-return-focus",
  "focus": ["main"],
  "suppress": ["possible-cookie-wall"],
  "threshold": 70,
  "priority": {
    "checkout*": "critical",
    "footer*": "low",
    "analytics*": "ignore"
  }
}

A configuração é detectada automaticamente a partir do diretório de trabalho (tactual.json ou .tactualrc.json). As flags de CLI são mescladas com as configurações do arquivo e as substituem.

Perfis de AT

PerfilPlataformaDescrição
generic-mobile-web-sr-v0MobilePrimitivas normalizadas de SR móvel (padrão)
voiceover-ios-v0MobileVoiceOver no iOS Safari — navegação baseada em rotor
talkback-android-v0MobileTalkBack no Android Chrome — controles de leitura
nvda-desktop-v0DesktopNVDA no Windows — teclas rápidas do modo de navegação
jaws-desktop-v0DesktopJAWS no Windows — cursor virtual com modo de formulários automático

Os perfis definem o custo de cada ação de navegação, os pesos das dimensões de pontuação, costSensitivity (escala a curva de decaimento de acessibilidade) e modificadores dependentes de contexto. Consulte src/profiles/ para detalhes de implementação.

Limitação do perfil mobile. Os perfis voiceover-ios-v0 e talkback-android-v0 modelam os custos de ação e o fraseado dos anúncios de SR com precisão, mas as sondas de teclado do Tactual (--probe) testam apenas interações de desktop (Tab, Enter, Escape). Elas NÃO simulam gestos de toque (toque único, toque duplo, deslizar para a direita, deslizar com três dedos, rotação do rotor, etc.). Para perfis mobile, as dimensões de pontuação refletem o custo previsto pelo modelo do perfil — não o comportamento medido. Testes em dispositivos reais continuam sendo necessários para verificar a acessibilidade móvel.

Modos visuais. Os perfis nvda-desktop-v0 e jaws-desktop-v0 declaram uma matriz visualModes (claro/escuro × cores forçadas ligado/desligado) para que o analisador capture o contraste de cada ícone sob cada combinação. Os perfis mobile e genérico omitem isso — o Modo de Alto Contraste do Windows não é uma preocupação realista para mobile. Consulte Verificações de visibilidade abaixo.

Verificações de visibilidade

Quando o perfil ativo declara uma matriz visualModes, o Tactual re-emula cada combinação de (colorScheme, forcedColors) após a captura inicial e amostra os estilos computados de cada ícone. O construtor de achados compara o fill computado de cada ícone com o background-color do ancestral não transparente mais próximo e emite uma penalidade quando o contraste fica abaixo do limite não textual da WCAG 1.4.11 (3:1).

Quatro redações de penalidade, três níveis de pontuação:

PenalidadeGatilhoImpacto na operabilidade
Icon invisible in <mode>Contraste < 1,5:1, sem rótulo de texto adjacenteOperabilidade limitada a 60
Decorative icon invisible in <mode>Contraste < 1,5:1, o controle tem rótulo de texto visívelOperabilidade −5
Low icon contrast in <mode>Contraste 1,5–3,0:1, sem rótulo de texto adjacenteOperabilidade −5
Author-set SVG fill in <mode>Contraste OK no Playwright (≥3:1), mas o modo é forced-colors: active e o preenchimento é um literal CSS do autor (não sistêmico, não currentColor)Operabilidade −2

A verificação ignora ícones que já são seguros para HCM: fill="currentColor", fill: ButtonText (ou qualquer cor do sistema), forced-color-adjust: none (opt-out do autor) ou fill === color computado (currentColor aplicado via CSS). Ícones de baixo contraste ao lado de um rótulo de texto visível são suprimidos por completo — o rótulo identifica o controle e o ícone é apenas reforço.

Por que o nível de risco de substituição existe. Diferentes temas de HCM do usuário têm valores diferentes de Canvas/ButtonText/cores do sistema. Um preenchimento literal do autor (ex.: svg { fill: #e4e6e6 }) pode ter bom contraste contra a paleta HCM padrão do Chromium, mas ruim contra um tema específico do usuário. A renderização do literal pelo navegador é consistente entre Playwright, Chrome e Edge para forced-color-adjust: preserve-parent-color (o padrão para caminhos SVG) — a preocupação concreta é a variabilidade do tema, não uma substituição oculta de pintura do SO. O Tactual sinaliza o padrão para que você saiba verificar no Edge real com um tema HCM representativo, não porque a medição de contraste do Playwright é enganosa.

Desative explicitamente via --no-check-visibility, checkVisibility: false em tactual.json ou checkVisibility: false na ferramenta analyze_url do MCP. Force a ativação via --check-visibility mesmo quando um perfil não declara modos (sem efeito sem modos).

A verificação adiciona aproximadamente +50–200ms por modo declarado por página — re-emular mídias é barato; não há novo contexto de navegador por modo.

Predefinições de pontuação

As predefinições agrupam filtros de foco e mapeamentos de prioridade para casos de uso comuns. Elas se sobrepõem aos arquivos de configuração e às flags de CLI (predefinição → tactual.json → flags de CLI).

PredefiniçãoCaso de usoFocoAlvos críticos
ecommerce-checkoutFluxos de compramaincheckout, cart, payment, buy
docs-siteDocumentaçãomain, navigationsearch, nav
dashboardAplicações webmain, navigationsave, submit, create, delete, search
form-heavyPáginas de formuláriomainsubmit, save, next, continue, error
npx tactual analyze-url https://shop.com --preset ecommerce-checkout
npx tactual presets  # list all presets with details

As predefinições suprimem banners de cookies e alvos de analytics por padrão. Para substituir, use --exclude ou defina priority em tactual.json. As predefinições não se compõem — apenas uma --preset pode estar ativa.

Pontuação

Cada alvo recebe um vetor de pontuação de 5 dimensões:

DimensãoO que mede
DescobribilidadeO usuário consegue perceber que o alvo existe?
AlcanceQual é o custo de navegação para chegar lá?
OperabilidadeO controle se comporta de forma previsível?
RecuperaçãoQuão difícil é se recuperar de ultrapassar o alvo?
Risco de interopQual a probabilidade de variação de suporte AT/navegador? (penalidade)

Os pesos das dimensões variam por perfil:

PerfilDROReccostSensitivity
generic-mobile-web-sr-v00.300.400.200.101.0
voiceover-ios-v00.300.350.200.151.1
talkback-android-v00.250.450.200.101.3
nvda-desktop-v00.350.250.300.100.7
jaws-desktop-v00.300.250.350.100.6

Composto: Média geométrica ponderada: overall = exp(sum(w_i * ln(score_i)) / sum(w_i)) - interopRisk. Cada dimensão é limitada a um mínimo de 1 antes do log para evitar log(0). Um zero em qualquer dimensão elimina a contribuição dessa dimensão para a média geométrica, reduzindo significativamente a pontuação geral — você não pode operar o que não consegue alcançar.

Faixas de severidade:

PontuaçãoFaixaSignificado
90-100ForteBaixa preocupação
75-89AceitávelMelhorável
60-74ModeradoDeve ser triado
40-59AltoProvável atrito significativo
0-39GraveProvavelmente bloqueante

Diagnósticos

O Tactual emite diagnósticos para confiabilidade de captura, estrutura da página, acesso visual, evidências de runtime, validade de ARIA e padrões de custo repetidos. Avisos são sugestões de revisão, não falhas automáticas de conformidade. Muitas verificações visuais/de conteúdo são heurísticas e devem ser confirmadas em contexto antes de registrar um defeito.

CódigoNívelSignificado
blocked-by-bot-protectionerroPágina de bot/desafio detectada; o conteúdo capturado não é a página pretendida.
empty-pageerroNenhum alvo encontrado.
okinfoA captura produziu um conjunto de alvos sem avisos de confiabilidade.
possibly-degraded-contentavisoSuspeita de poucos alvos para uma página HTTP.
sparse-contentavisoApenas 1-4 alvos encontrados.
possible-login-wallavisoSuspeita de conteúdo restrito por autenticação ou redirecionamento de login.
possible-cookie-wallinfoO consentimento de cookies pode obscurecer o conteúdo.
redirect-detectedinfo/avisoA captura caiu em uma URL ou domínio diferente.
timeout-during-renderavisoUma espera de renderização solicitada não foi concluída antes da captura.
framework-detectedinfoSinais de framework frontend foram detectados durante a captura.
spa-route-changesinfoMudanças de rota SPA aconteceram durante a análise.
exploration-no-new-statesaviso--explore foi executado, mas não revelou estados adicionais.
frames-descendedinfoA descida em iframes capturou ou pulou quadros filhos.
auto-scrolledinfoA rolagem automática foi executada antes da captura e relata o que surgiu.
banners-dismissedinfoA dispensa do banner de cookies/consentimento foi tentada.
tab-order-walkedinfo/avisoA varredura por ordem de tabulação registrou paradas de foco; avisa em tabindex positivo.
viewport-divergenceavisoDiferença de viewport desktop/mobile encontrou alvos, marcos ou títulos ausentes.
no-headingsavisoNenhum elemento de título (heading) encontrado.
heading-skipavisoA hierarquia de títulos pula um nível, como h1 -> h3.
empty-headingavisoO título existe, mas não tem texto.
numeric-headingavisoO texto do título é apenas dígitos, pontuação ou conteúdo trivial de um caractere.
h1-countinfo/avisoA página não tem um H1 único útil, ou tem vários H1s que valem revisão.
no-landmarksavisoNenhuma região de marco (landmark) encontrada.
no-main-landmarkavisoMarco <main> ausente.
no-banner-landmarkinfoMarco <header> / banner ausente.
no-contentinfo-landmarkinfoMarco <footer> / contentinfo ausente.
no-nav-landmarkinfoMarco <nav> / navegação ausente.
landmark-demotedavisoO marco HTML existe, mas é rebaixado pelo contexto de aninhamento.
structural-summaryinfoVisão geral estrutural de uma linha.
no-skip-linkavisoNenhum link "pular para o conteúdo" em páginas com 5+ alvos.
broken-skip-linkavisoLink estilo "pular" aponta para um alvo de fragmento ausente.
skip-link-not-firstavisoUm link de pular existe, mas não é alcançável nas duas primeiras paradas de Tab.
visual-order-divergenceavisoA ordem visual parece divergir da ordem de navegação DOM/SR.
shared-structural-issueavisoUma penalidade que afeta >50% dos alvos é promovida ao nível da página.
redundant-tab-stopsavisoMúltiplos alvos de link criam paradas de Tab repetidas para o mesmo destino.
data-flow-dependenciesinfoEstados explorados revelam controles que só são habilitados após ação anterior.
form-summaryinfo/avisoResume formulários e avisa quando um formulário parece não ter controle de envio.
missing-autocompleteavisoCampos de formulário padrão não têm tokens autocomplete úteis ou os desabilitam.
empty-interactiveavisoAlvo interativo sem nome acessível.
fake-interactive-elementsavisoElementos não semânticos clicáveis não são alcançáveis por teclado/SR.
cdp-click-listenersavisoCDP encontrou listeners de clique em elementos não interativos.
ambiguous-link-namesavisoLinks com o mesmo nome acessível apontam para destinos diferentes.
media-without-controlsavisoÁudio/vídeo sem controles e não oculto.
duplicate-idavisoValores duplicados de id podem quebrar rótulos e referências ARIA.
nested-interactiveavisoControles interativos aninhados dentro de outros controles interativos.
meta-refreshavisoA página atualiza ou redireciona automaticamente via meta refresh.
missing-image-altavisoImagens sem atributos alt.
suspicious-image-altavisoTexto alternativo de imagem parece preenchimento ou placeholder tipo nome de arquivo.
missing-iframe-titleavisoIframes sem title ou rótulo acessível.
missing-html-langaviso<html lang> ausente ou não parece uma tag de idioma BCP 47.
poor-document-titleavisoTítulo do documento ausente, vazio, curto demais ou genérico.
viewport-blocks-zoomavisoConfigurações de viewport meta restringem o zoom do usuário.
low-contrast-textavisoTexto interativo ou títulos falham nos limites de contraste de texto estilo WCAG.
color-only-conveyanceavisoTexto parece depender apenas de cor para transmitir significado.
color-blindness-contrast-failavisoTexto perde contraste sob deficiência simulada de visão de cores.
lang-switch-without-markeravisoO idioma do texto parece mudar sem um marcador lang.
invalid-aria-roleavisoPapel ARIA não padrão presente.
unknown-aria-attravisoAtributo aria-* desconhecido presente.
invalid-aria-attr-valueavisoValor de atributo ARIA fora do conjunto de valores permitidos.
missing-required-aria-attravisoPapel ARIA sem estado ou propriedade obrigatória.
aria-naming-prohibitedavisoNome aplicado a um papel que proíbe nomeação.
unsupported-aria-attr-for-roleavisoAtributo ARIA não suportado no papel do elemento.

Exploração

A flag --explore ativa exploração de ramos limitada:

  • Abre menus, abas, disclosures, accordions e diálogos
  • Captura novos estados de acessibilidade de UI oculta
  • Marca alvos descobertos como requiresBranchOpen
  • Respeita orçamentos de profundidade, contagem de ações, contagem de alvos e novidade
  • Política de ação segura bloqueia interações destrutivas

A exploração é útil para páginas com UI oculta significativa (ex.: menus suspensos, interfaces com abas, diálogos modais).

Candidatos à exploração são ordenados por uma chave estável (papel + nome) antes da iteração, para que o mesmo conteúdo de página produza a mesma ordem de exploração entre execuções.

Sondas

A flag --probe mede se padrões interativos importantes funcionam após aparecerem na árvore de acessibilidade. As sondas são opt-in porque enviam eventos reais de teclado e adicionam tempo de execução. Desde 0.4.0, isso inclui verificações genéricas de foco/ativação, contratos de menu, contratos de diálogo modal, fluxos de gatilho para diálogo, abas, disclosures, comboboxes, listboxes e fluxos de erro de campo obrigatório. Os achados das sondas incluem resumos de evidências para que os relatórios distingam falhas medidas de pontuação modelada ou heurística.

Controles orientados a objetivos mantêm sondas profundas úteis em SPAs complexos:

NecessidadeCLICampo MCP/AçãoEfeito
Analisar uma subárvore--scope-selector "#drawer"scopeSelector / scope-selectorCaptura, pontua e sonda apenas a(s) subárvore(s) selecionada(s).
Sondar uma subárvore--probe-selector "#drawer"probeSelector / probe-selectorMantém a pontuação em toda a página, mas gasta o orçamento de sondas apenas dentro da(s) subárvore(s) selecionada(s).
Abrir um ramo primeiro--entry-selector "[aria-controls='menu']"entrySelector / entry-selectorAtiva o gatilho antes da captura/sonda e prioriza alvos recém-revelados.
Mirar em um alvo conhecido--goal-target "checkout"goalTarget / goal-targetRestringe a sondagem a ids, nomes, papéis, tipos ou seletores de alvo correspondentes.
Mirar por glob--goal-pattern "*dialog*"goalPattern / goal-patternIgual ao alvo de objetivo, com correspondência por glob.
Gastar orçamento por intenção--probe-strategy modal-return-focusprobeStrategy / probe-strategyExecuta as famílias de sondas relevantes para all, overlay, composite-widget, form, navigation, modal-return-focus ou menu-pattern.

Por exemplo, para avaliar um ramo modal sem rastrear menus não relacionados:

npx tactual analyze-url https://app.example.com/settings \
  --profile nvda-desktop-v0 \
  --probe \
  --entry-selector "[aria-controls='profile-dialog']" \
  --probe-strategy modal-return-focus \
  --format markdown

Orçamentos de exploração

OrçamentoFlag CLIPadrãoPropósito
Profundidade--explore-depth3Profundidade máxima de recursão
Ações--explore-budget50Orçamento total de cliques em todos os ramos
Alvos--explore-max-targets2000Parar se os alvos acumulados excederem isso
Tempo--explore-timeout60000 msLimita o tempo total de exploração, incluindo sondas iniciais, capturas de ramos e sondas de estados revelados

Orientação de dimensionamento:

Tipo de páginaConfigurações sugeridasPorquê
Site de marketing, página de documentação, blogpadrõesSuperfície pequena, padrões raramente atingidos
Dashboard com barra lateral/menu--explore-depth 3 --explore-budget 50 (padrões)Captura um nível de aberturas de menu
Aplicativo complexo (Figma, Notion, etc.)--explore-depth 4 --explore-budget 100 --explore-max-targets 5000Menus mais profundos, mais estado
Páginas com UI oculta muito grande (seletores de emoji, grades de cores)--explore-max-targets 10000 mais --exclude "emoji-*"Limitar ou filtrar o fluxo excessivo
Triagem rápida de página desconhecida--explore-depth 1 --explore-budget 10Apenas abrir ramos óbvios, rápido

Se a exploração atingir o tempo limite antes de abrir ramos úteis, aumente --explore-timeout e --explore-budget lentamente, ou use --entry-selector, --probe-selector e --probe-strategy para gastar o mesmo orçamento no ramo que você deseja. Se a saída tiver alvos com aparência duplicada, reduza --explore-depth (recursão profunda pode redescobrir os mesmos elementos por caminhos diferentes).

Detecção de framework SPA

O Tactual detecta quando o conteúdo SPA foi renderizado antes de capturar a árvore de acessibilidade. Frameworks detectados: React, Next.js, Vue, Nuxt, Angular, Svelte e SvelteKit. Sinais genéricos de conteúdo HTML5 (marcos, títulos, navegação, links) também são verificados. Para SPAs não cobertos pela detecção automática, use --wait-for-selector (CLI) ou waitForSelector (MCP/API) para especificar um seletor CSS que indique que seu aplicativo foi hidratado.

Após a detecção inicial do framework, o Tactual usa polling baseado em convergência — capturando repetidamente a árvore de acessibilidade até que a contagem de alvos se estabilize — o que funciona independentemente do framework.

Para aplicativos com muitos SPAs, estes auxiliares de captura opt-in são úteis:

npx tactual analyze-url https://app.example.com \
  --wait-for-selector "main" \
  --detect-routes \
  --auto-scroll \
  --descend-frames \
  --diff-viewports
  • --detect-routes registra eventos de pushState, replaceState, popstate e hashchange que ocorrem durante a análise.
  • --auto-scroll expõe conteúdo preguiçoso orientado por IntersectionObserver antes da captura.
  • --descend-frames anexa alvos de iframe com atribuição de URL do quadro. Iframes de mesma origem usam o snapshot de acessibilidade com escopo de quadro do Playwright; Chromium usa CDP como fallback para OOPIFs de origem cruzada quando o caminho normal de snapshot está inacessível. Firefox/WebKit mantêm o comportamento de pular quadros inacessíveis.
  • --diff-viewports captura conteúdo de alvo, marco ou cabeçalho que desaparece entre viewports de desktop e mobile.
  • --dismiss-banners, --probe-hover e --walk-tab-order adicionam evidências de runtime direcionadas para bugs comuns de sobreposição em SPAs e de ordem de foco.

Benchmark de páginas conhecidas

Para evidências de lançamento contra páginas públicas complexas de SPA/biblioteca de componentes, execute:

npm run benchmark:known-pages

O script compila o pacote, executa analyze-url com a pilha de helpers de SPA habilitada e grava run-results.json, summary.json e REPORT.md em build/known-pages-*. Ele não é intencionalmente um gate de CI: sites públicos mudam, bloqueiam automação e servem conteúdo diferente ao longo do tempo. Use o relatório para identificar desvios e surpresas por categoria e, em seguida, use fixtures locais ou páginas de propriedade do projeto para gates de regressão determinísticos. Para um smoke run limitado ou sondas de qualidade de captura APG/W3C, chame o script diretamente, por exemplo node scripts/known-pages-corpus.mjs --build --limit 1 ou node scripts/known-pages-corpus.mjs --build --include-capture-probes.

Rastreamento de Regressão

Compare duas execuções de análise para detectar regressões:

# Save a baseline
npx tactual analyze-url https://your-app.com --format json --output baseline.json

# After changes, run again and diff
npx tactual analyze-url https://your-app.com --format json --output candidate.json
npx tactual diff-results baseline.json candidate.json

O diff mostra alvos que melhoraram, regrediram ou mudaram de severidade, além de penalidades resolvidas e adicionadas. Em CI, use a entrada de ação comment-on-pr para publicar resultados automaticamente em cada pull request.

Risco de Interoperabilidade

Tactual inclui um snapshot estático de dados de suporte a papéis/atributos ARIA derivado de a11ysupport.io e do projeto ARIA-AT. Papéis com lacunas conhecidas de suporte entre AT/navegadores recebem uma penalidade de risco de interoperabilidade.

PapelRiscoNota
button, link, heading0Bem suportado
dialog5Gerenciamento de foco varia
combobox8Padrão mais problemático para interoperabilidade
tree10Pouco suportado fora do JAWS
application15Perigoso se mal utilizado

Interpretando Descobertas

As descobertas do Tactual misturam intencionalmente vários domínios de evidência:

  • Navegação por leitor de tela: marcos, cabeçalhos, rótulos, descoberta de ramificações, custo de travessia sequencial e anúncios modelados.
  • Operabilidade por teclado: movimento de foco, ativação, recuperação com Escape, aprisionamento de Tab e sondas de widgets em runtime.
  • Semântica estrutural: nomes ausentes, estrutura de cabeçalho/marco, marcos rebaixados, causas compartilhadas repetidas.
  • Risco de interoperabilidade: papéis e estados com lacunas conhecidas de suporte entre AT/navegadores.
  • Verificações adjacentes a ponteiro: problemas de tamanho de alvo e visibilidade de ícones que podem afetar usuários fora do modelo de navegação por leitor de tela.

Isso significa que uma página pode ter uma pontuação forte de navegação por leitor de tela e ainda receber avisos de link de pular, tamanho de alvo ou visibilidade. Trate-os como categorias de correção separadas, em vez de contradições.

Descobertas de APG derivadas de sondas são avisos de consistência medidos. Muitos widgets têm variantes de implementação válidas, especialmente comboboxes e padrões semelhantes a disclosure, então verifique o aviso contra o padrão pretendido antes de tratá-lo como uma substituição obrigatória. Fluxos críticos ainda devem ser verificados com a combinação de navegador/AT alvo.

Recomendações de Formato de Saída

FormatoTamanho típicoMelhor para
console~8KBRevisão humana no terminal
markdown~11KBPRs e comentários de issues
json~18KBConsumo programático
sarif~4-40KBGitHub Code Scanning / CI

Todos os formatos de relatório não-SARIF emitem saída resumida por padrão: estatísticas, issues agrupadas, candidatos a remediação, resumos de evidência e piores descobertas (limitadas a 15). SARIF limita a 25 resultados. Quando a saída é truncada, uma nota aparece no topo. A API da biblioteca expõe o AnalysisResult completo; a saída do relatório CLI e MCP é intencionalmente compacta, a menos que um campo específico como includeStates seja solicitado.

Para uso via MCP, sarif é o formato padrão e recomendado. Use summaryOnly: true para uma verificação de saúde compacta com estatísticas, contagens de severidade, diagnósticos e as 3 principais issues.

Calibração

Tactual inclui uma estrutura de calibração (src/calibration/, exportada como tactual/calibration) para ajustar parâmetros de pontuação contra conjuntos de dados de verdade fundamental. Consulte docs/CALIBRATION.md para detalhes.

Observações de calibração também podem incluir feedback determinístico de anúncios de trabalho de revisão OSS: registre observedAnnouncement quando você souber a saída testada, ou observedAnnouncementTokens quando a frase exata for ruidosa, mas os tokens de papel/nome/estado forem claros. Tactual compara esses com seu anúncio modelado para o alvo correspondente e relata tokens ausentes ou inesperados. Use tactual calibration-report ou MCP calibration_report para executar um conjunto de dados contra a saída salva de analyze-url --full-json e emitir scoringSignals. Use tactual observe-announcement para gerar ou anexar observações somente de anúncio de uma análise salva, ou npm run -- nvda:vm:observe -- ... neste repositório para organizar uma pasta de captura controlada de VM NVDA. O corpus versionado do repositório vive em calibration/corpus/; execute npm run calibration:corpus para auditar gates de cobertura e npm run calibration:matrix após npm run build para classificar o trabalho de ajuste de alcance por MAE, viés, variância e desvio de plano de sequência obsoleto.

Prontidão de lançamento e limites conhecidos estão documentados em docs/RELEASE_TEST_MATRIX.md, docs/LIMITATIONS.md e docs/NVDA_VM_OBSERVER.md.

Desenvolvimento

npm install                    # Install dependencies
npm run build                  # Build with tsup
npm run test                   # Run unit + integration tests
npm run test:shard -- --list   # List bounded Vitest release shards
npm run test:shard -- capture  # Run one bounded Vitest shard
npm run test:shards            # Run all bounded Vitest shards
npm run test:benchmark         # Run benchmark suites
npm run typecheck              # TypeScript type checking
npm run lint                   # ESLint
npm run test:release           # Full split release gate

Segurança

Sandboxing do navegador

Tactual sempre executa Playwright com sandboxing padrão do Chromium habilitado. Ele nunca desativa a segurança da web ou modifica o modelo de segurança do navegador. Todas as interações de página acontecem dentro do sandbox padrão do processo Chromium.

Política de ação segura

Quando a exploração está habilitada (--explore), Tactual classifica elementos interativos em três níveis antes de ativá-los:

NívelAçãoExemplos
SeguroAtivadoAbas, itens de menu, disclosures, accordions, âncoras da mesma página
CautelaAtivado com cuidadoLinks externos, botões ambíguos
InseguroPuladoBotões de envio (fora de formulários de busca), Excluir, sair, comprar, implantar, cancelar assinatura

Esta é uma heurística baseada em palavras-chave — ela não pode detectar engano semântico (por exemplo, um botão "Salvar" que na verdade exclui dados) ou inspecionar comportamento no servidor. Para uso em produção, sempre execute exploração contra ambientes confiáveis ou em sandbox.

Validação de URL

Todas as URLs são validadas antes da navegação. O CLI aceita esquemas http:, https: e file: para que fixtures locais funcionem; ferramentas MCP que aceitam URLs aceitam apenas http: e https: para evitar expor arquivos locais através de navegação de navegador controlada por agente. javascript:, data:, blob: e vbscript: são rejeitados. URLs com credenciais incorporadas (por exemplo, https://user:pass@host/) também são rejeitadas. Faixas de IP privadas/internas não são filtradas — executar Tactual em um ambiente com acesso a serviços internos é equivalente a permitir que qualquer outra ferramenta orientada por Playwright os alcance, então trate a entrada de URL como entrada confiável.

Licença

Apache-2.0

Atribuição

A frase de papel/estado do simulador é calibrada contra o projeto W3C ARIA-AT, que é licenciado sob CC-BY 4.0. Tactual não inclui dados ARIA-AT; o script de calibração (npm run calibrate) busca asserções do repositório upstream em tempo de execução. Se você publicar resultados de calibração do Tactual, por favor atribua o projeto W3C ARIA-AT como a fonte das asserções de verdade fundamental.

Dados de suporte a papéis/atributos ARIA referenciados na pontuação de risco de interoperabilidade são derivados de a11ysupport.io e do mesmo projeto ARIA-AT.