Do uso à experiência
Um relato nomeia um sintoma. O trabalho é a experiência por trás dele. « O cliente desaparece quando a conversa vai para o assunto » é um bug. « Uma conversa reúne o que é sobre ela: o cliente fica quando seu assunto é adicionado » é o que construir, verificar e filmar. Escreva essa frase primeiro. Corrija a estrutura que permitiu o sintoma, depois prove a frase usando o produto.
O loop
- Colete o uso. Leia o relato, depois os vestígios de uso real: as conversas da pessoa, diários, logs, presença, os arquivos que ela tocou. Eles guardam expectativas que ninguém escreveu (« eles estão onde? » espera os pontos em si, não um resumo).
- Escreva a experiência. Uma frase por relato, presente, do lado da pessoa, sem palavras de implementação. Mantenha a lista. Ela se torna a narração do filme e as mensagens das afirmações.
- Encontre a causa estrutural. Pergunte por que o produto poderia fazer isso. Uma causa geralmente explica vários relatos (identidade retirada de um nome de exibição; duas contagens que compartilham uma palavra; um renderizador que descarta uma classe ao inserir). Corrija a causa, não a tela que a mostrou.
- Use você mesmo. Dirija o aplicativo real como cada pessoa envolvida, em largura de desktop e telefone, através do namespace browser (abaixo). Olhe para capturas de tela. Conte o que a página diz, não o que o código pretende.
- Mantenha. Transforme os passos manuais em um cenário: ações viram eventos, verificações viram afirmações, a frase da experiência vira a narração da cena. Coloque as voltas do modelo em fita para que o filme seja reproduzido em segundos, sem custo.
- Relate a experiência, não o patch. No resumo, lidere com o que a pessoa encontrará agora, depois a causa, depois o filme e como reproduzi-lo.
Gosto da casa (o que Othman pediu, repetidamente)
- Menos cópia. O estado é desenhado: tom, peso, posicionamento, um anel, uma marca. Uma frase que explica uma tela significa que a tela está errada.
- Uma palavra por ideia. Mantenha um glossário e segure-o: um « critère » (julgado contra o procedimento) nunca é um « point » (o que uma pessoa decide). Se duas contagens compartilham uma palavra, alguém as somará.
- As coisas se acumulam. Tags se somam (tipo, depois cliente, depois assunto). A atual é preenchida e as outras permanecem como contornos. Nunca substitua o contexto que a pessoa já viu.
- Números desenhados antes do texto. Um histórico abre em gráficos, uma série cada, valores rotulados. O texto fica embaixo, uma linha por evento, e abre sob demanda.
- Cada referência leva ao seu lugar. Um número de parágrafo rola até o parágrafo e o ilumina. Uma citação encontra sua passagem. A barra de rolagem marca onde as coisas estão, em suas cores.
- Ao vivo por padrão. Sem recarregamentos completos. Uma alteração feita por uma pessoa aparece em todas as páginas abertas ao mesmo tempo. Toques repetidos em uma página lenta não devem repetir o efeito: gestos são idempotentes.
- Controles onde a coisa está, e apenas para quem pode usá-los. Pessoas somente leitura veem o estado sem o controle.
- Saiba quem está lá. Identidade e função alcançam todas as telas e todos os agentes. Não diga a um parceiro que « um parceiro deve confirmar ».
- Limites honestos. Diga claramente o que o produto ainda não faz. Nunca aponte para uma tela que não pode fazê-lo.
- Largura de telefone é um leitor de primeira classe: margens de 16px, sem rolagem horizontal (
minmax(0,1fr), não1fr), e a conta sempre acessível. - Mockups e narração na linguagem do produto (francês para Knowledger).
Testando manualmente com o namespace browser
O navegador nativo do Beam Lisp (optional/browser-port na árvore beam-lisp) executa Chromium com cabeçalho em um Sway headless privado, com entrada confiável e uma transmissão de tela contínua. É o mesmo objeto que um cenário dirige, então uma sessão manual se transforma em um teste sem ser reescrita. Use agent-browser para uma olhada rápida. Use o namespace browser para qualquer coisa que valha a pena manter.
Uma vez por máquina
cd ~/projects/beam-lisp/optional/browser-port
nix develop --command cargo build --release --locked --features native-browser
nix build .#runtime-wayland --out-link ~/.local/share/bl-browser/runtime-wayland # chromium, sway, wayvnc
command -v ffmpeg || nix profile add nixpkgs#ffmpeg
Execute qualquer coisa que use com bl run -p ~/projects/beam-lisp/optional/browser-port/bl …
(ou bl test -p …).
Uma sonda: um arquivo, uma pessoa, entrada real
templates/probe.bl é o ponto de partida. Seu núcleo:
(ns probe (:require [browser.page :as page]))
(def rt (str (System/get_env "HOME") "/.local/share/bl-browser/runtime-wayland/bin/"))
(def p (page/open! {:executable (str (System/get_env "HOME") "/projects/beam-lisp/optional/browser-port/target/release/bl-browser-port")
:width 1440 :height 860
:launch {"profile" "/tmp/probe/profile" "runtime" "/tmp/probe/runtime"
"chromium" (str rt "chromium") "compositor" (str rt "sway") "vnc" (str rt "wayvnc")
"width" 1440 "height" 960}}))
(try
;; quem está olhando: a identidade que o proxy adicionaria (aqui cabeçalhos Tailscale); alcança o socket ao vivo também
(page/cdp! p "Network.enable" {})
(page/cdp! p "Network.setExtraHTTPHeaders" {"headers" {"tailscale-user-login" "[email protected]" "tailscale-user-name" "timinou"}})
(page/record! p "/tmp/probe/take.mp4" {:fps 24}) ; opcional: a sessão inteira como um filme
(page/navigate! p "http://127.0.0.1:24025/a/sahel-…")
(page/wait! p "document.documentElement.dataset.live==='1'") ; um predicado JS, limite de 30 s por padrão
(page/click! p ".rv-rail a.para[data-goto]") ; ponteiro confiável: move, pressiona, solta
(println (page/evaluate! p "scrollY")) ; pergunte à página o que uma pessoa veria
(page/screenshot! p "/tmp/probe/after.png") ; então OLHE para ela
(page/stop-recording! p)
(finally (page/close! p)))
Os verbos são navigate! wait! click! hover! fill! key! drag! evaluate! screenshot! record! stop-recording! show-cursor! cdp!. cdp! alcança qualquer outra coisa que o Chromium oferece:
viewport, rede, cookies, emulação (Emulation.setDeviceMetricsOverride para um telefone).
Hábitos que fazem uma sonda valer a pena ser mantida
- Pergunte à página, não ao código. Cada verificação é uma expressão JS que retorna
truequando uma pessoa veria a coisa: contagens de linhas, o texto de uma tag,scrollY, uma classe no elemento sob o ponteiro. Essas expressões se tornam afirmações sem alteração. - Selecione pelo significado. Dê ao aplicativo atributos de dados estáveis onde os testes
precisam deles (
button.cell[data-person='Karim Saadi'][data-team='Associés']), nunca « o quinto botão ». - Seja cada pessoa. Abra uma página por pessoa com sua identidade. Duas páginas lado a lado é como « ao vivo » é provado: uma age, a outra muda sem recarregar.
- Verifique a primeira pintura e a página corrigida. Aplicativos ao vivo renderizam HTML uma vez, depois corrigem a partir dos dados. Bugs se escondem na diferença (uma classe descartada ao inserir, uma lista começando com texto lido como nome de tag). Alcance cada tela uma vez por URL e uma vez navegando até ela.
- Aguarde a página ficar ao vivo, não apenas conectada. Um cliente ao vivo pode
substituir a página renderizada pelo servidor pela primeira renderização do seu socket. Texto digitado
entre eles é perdido, para um teste e para uma pessoa digitando rapidamente após o carregamento.
O aplicativo deve manter o que foi digitado durante essa montagem e então dizer que está ao vivo
(
data-mounted). Testes aguardam essa flag. - Olhe para a largura do telefone. Verifique
document.documentElement.scrollWidth === innerWidtha 390px, depois olhe para a captura de tela. - Nunca toque em dados reais, e prove isso. Aponte o aplicativo para uma cópia reflink
de seus dados (
cp -a --reflink=auto) e uma porta sobressalente. Depois prove o isolamento antes de confiar: renomeie uma coisa na cópia (um canário: uma equipe « AssociésX »), aja sobre ela e verifique se a cópia mudou e o timestamp do arquivo real não mudou. Faça isso uma vez por tipo de processo que escreve (manipuladores de página, sockets ao vivo, trabalhos em segundo plano). No Beam Lisp,System/put_envde um teste alcança manipuladores de página, mas não sockets ao vivo: um socket que não lê uma pasta de dados configurada cai de volta para o padrão, que são os dados reais. O aplicativo deve fixar sua configuração em toda a VM quando seu servidor inicia (persistent_term) e lê-la de lá. Se você precisar tocar em dados ao vivo, tire um instantâneo do arquivo, aja, faça diff para confirmar apenas sua alteração, restaure.
Da sonda ao filme
Um scenario.demo/defdemo é um teste comum (bl test). Os passos mapeiam um a um:
| Sonda | Cenário |
|---|---|
(page/navigate! p url) | (s/does :othman [:navigate url]) |
(page/wait! p js) | (s/does :othman [:wait js]) |
(page/click! p sel) / hover! / fill! / key! | [:click sel] [:hover sel] [:fill sel text] [:key "Enter"] |
| uma pausa para o olho | [:pause ms] |
(page/evaluate! p js) que deve ser verdadeiro | (s/sees :othman (fn [p _] (= true (page/evaluate! p js))) "a experiência") |
| uma pessoa | um ator em browser.film/owned-worlds, embrulhado para definir sua identidade ao abrir |
| um parágrafo de narração | (demo/scene :id {:title … :say … :capture :video} eventos…) |
templates/feature-demo.bl é um arquivo completo: uma cópia isolada dos dados do aplicativo,
o aplicativo iniciado na VM de teste em uma porta sobressalente, mundos gravados com
identidades, trilhas silenciosas quando nenhuma chave de voz existe, e uma demonstração com três
cenas. Exemplo funcional: knowledger-interface-review/apps/practice/test/features-demo.bl
(cinco filmes: revisão, histórico, peças, uma equipe alterada ao vivo entre duas pessoas, uma
conversa gravada).
Escreva cenas como a experiência, não a correção: « Cada ponto leva ao seu lugar », nunca « corrija o manipulador §-link ». A narração é a documentação.
Voltas do modelo em fita
Qualquer coisa que um agente faça deve passar pela própria porta de ferramentas do aplicativo, para que apenas as escolhas do modelo sejam do modelo. Uma fita mantém, para uma execução do modelo, as chamadas de porta que ele fez em ordem e sua resposta final, indexadas por um hash do modelo, prompt do sistema e prompt (com relógios, números tipo época e ids hex mascarados).
record: reproduz o que está na fita, executa o modelo para o que não está, mantém.replay(o padrão): uma execução não na fita é uma volta de erro. Uma reprodução nunca cai de volta para o modelo em silêncio.- Reproduzir faz as mesmas chamadas através da mesma porta, ritmado, para que o produto faça o trabalho novamente e a tela mostre, em segundos e de graça.
Fixe tudo que alcança o prompt (o nome da empresa, a data se houver) nos dados
de teste, ou a chave se desviará. Comprometa as fitas. Implementação de referência:
apps/practice/src/practice/cassette.bl e seus dois ganchos em conversation.bl
(a volta e a porta).
Executando e renderizando
bl test -p ~/projects/beam-lisp/optional/browser-port/bl app/test/features-demo.bl # reproduzir, provar, capturar
DEMO_RECORD=1 bl test -p … # colocar voltas de modelo ausentes na fita (precisa de credenciais do modelo)
BL_DEMO_EXPORT=1 bl test -p … # também renderizar MP4 + legendas + capítulos por filme
Cada filme limpa sua última captura em seu fixture, porque uma gravação nunca
sobrescreve uma. Mantenha cada narração dentro de duas linhas de legenda (cerca de 130
caracteres), ou a renderização recusa. Uma máquina carregada pode matar de fome o
codificador de transmissão de tela: verifique frames/recordings.json, onde encodedFrames
deveria ser cerca de segundos × fps, e execute novamente quando uma captura estiver curta.
Renderização (scenario.film/export!) precisa de Python 3 e FFmpeg com libass.
A narração é falada quando DEEPGRAM_API_KEY está definido. Caso contrário, cada cena recebe uma
trilha silenciosa tão longa quanto sua legenda leva para ler. Nunca assuma que uma chave de voz
exista. Navegue pelos filmes com (scenario.demo/serve! dir {:port 4163}) em
loopback, ou publique com work serve.
Antes de dizer que está pronto
- Cada item relatado tem sua frase de experiência, sua causa e uma afirmação que prova em um navegador real, como cada pessoa preocupada.
- Largura de desktop e telefone vistas, em capturas de tela, não apenas afirmadas.
- Primeira pintura e página corrigida ambas verificadas para cada tela tocada.
- Comportamento ao vivo provado com duas pessoas, onde importa.
- Nenhum dado real alterado pelo teste. Qualquer coisa tocada é restaurada, com o diff mostrado.
- Filmes reproduzidos a partir da fita sem rede. Fitas e cenários são comprometidos, renderizações não.
- O resumo lidera com o que a pessoa encontrará agora.