Tech Lead's Club - Spec, Lean (Especificação, Enxuta)
Congele as obrigações. Liberte o plano. Prove com alguém que não o construiu. Derivado de tlc-spec-driven 3.3.0 (Felipe Rodrigues), tlc-plan e tlc-implement.
┌────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ PLANO │ → │ VERIFICAÇÕES │ → │ CONSTRUÇÃO │ → │ VERIFICAR │
└────────┘ └──────────┘ └──────────┘ └──────────┘
leia-o obrigações sua sempre
Quatro movimentos, dois artefatos antes do código, um depois. Um humano confirma o que deve ser verdade e como está sendo construído em um documento, e só então qualquer parte disso se torna uma obrigação com uma prova anexada. Não há divisão em tarefas, e o plano não carrega um catálogo de componentes: o que é difícil de reverter recebe uma porta unidirecional com sua forma literal, e tudo que é reversível é decidido durante a construção e revisado no diff.
Por que esta forma
A falha dominante de um agente de codificação não é raciocínio ruim, é um requisito que foi lido mas nunca se tornou uma obrigação ativa - e então uma alegação de conclusão em cima disso. A mitigação que mede bem é um conjunto pequeno, congelado e externo de obrigações mais um verificador que não é o autor; uma auto-verificação reproduz o ponto cego do próprio autor. Portanto, este skill gasta seu orçamento nessas duas coisas e se recusa a gastá-lo coreografando como o modelo funciona.
Duas consequências que vale a pena declarar desde o início, porque são o que torna isso diferente de um fluxo tradicional orientado por especificações:
- Granularidade não é qualidade. Dividir uma funcionalidade em quinze tarefas de um arquivo compra ordenação, não correção, e custa uma releitura do processo em cada tarefa. Cobertura de prova compra correção.
- Um plano que o modelo deve obedecer compete com as obrigações pela atenção. Campos como
Onde,Ferramentas,Depende desão decisão do modelo, então não são escritos.
Regras críticas
O conjunto fixo. Estas valem mesmo se nenhum arquivo de referência for lido, e são as únicas regras que nunca diminuem com o perfil.
- Toda verificação é uma afirmação observável com um valor concreto mais a prova - o teste ou comando cujo código de saída a resolve. Sem prova, sem verificação.
- Testes afirmam o que as verificações dizem, nunca o que o código eventualmente faz. Nunca escreva um teste lendo a implementação.
- Nunca enfraqueça uma afirmação, exclua um teste ou pule um para fazer uma suíte passar. Uma verificação genuinamente errada é uma parada-e-pergunta, não uma edição.
- As verificações e as linhas da
Política de testessão fixas após aprovação. No design,Landing(Aterrissagem),Relations(Relações) eSurface(Superfície) são aditivas - uma porta descoberta durante a construção ganha uma linha antes do código que a fecha, e uma linha que o usuário aprovou nunca é reescrita.Flow(Fluxo) eImpact(Impacto) não são nem uma coisa nem outra: eles são mantidos verdadeiros, então um caminho diferente muda o salto no commit desse caminho. - O Verificador é um subagente novo, nunca o autor, nunca opcional, nunca esperando para
ser chamado. Quem detém a funcionalidade completa o despacha após o último commit da funcionalidade
ser feito - em
<base da funcionalidade>..HEAD, com todas as verificações. Nunca por um construtor, e nunca como filho de um. Um construtor termina, relata e para. O trabalho não está concluído no último commit; está concluído quando o relatório do Verificador dá conta de todas as verificações. - O perfil é um piso e não é um segredo. O relatório de verificação o nomeia, ou "nenhuma falha injetada" parece exatamente como esquecer de injetá-las.
- A porta de conclusão é um script, não uma intuição:
validate_verification.pydeve sair com código 0. - Raio de explosão: uma especificação aprovada autoriza edições locais e commits locais.
git push, deploy e mudanças em dados de produção precisam de uma autorização explícita para essa ação.
Perfil
O projeto declara o quanto é executado, em AGENTS.md ou equivalente. Na ausência de uma declaração:
light. Mesmos três níveis de tlc-implement, com a mesma proteção, então mover entre os dois
skills não precisa de um segundo vocabulário.
## tlc-spec-lean
profile: light
budget: 150k
| Perfil | Adiciona | Não consegue capturar |
|---|---|---|
light (padrão) | provas executadas em HEAD com cada teste nomeado mostrado existir e executar, uma afirmação localizada por verificação, lacunas de nível e amostragem, Swept existing (Varredura existente) relido | um membro do conjunto sem prova; um teste que passaria sob uma implementação errada |
standard (padrão) | a junção de Coverage (Cobertura) recalculada, linhas da Test policy (Política de testes) com um veredito cada, uma falha por superfície de afirmação | uma verificação que contradiz uma fonte vinculante; uma tela que ninguém construiu |
ui (interface) | fontes vinculantes abertas e comparadas, enumeração por tela de cópia e arranjo | apenas espaçamento, cor e peso da fonte, enumerados por tela |
Cada passo adiciona uma classe de falha detectada, então um perfil barato não é um desconto no mesmo
produto - leia a coluna da direita antes de escolhê-lo. Duas coisas sobre light valem ser ditas
em voz alta, porque sua própria linha as diz e é fácil passar por elas: ele não notará
um membro de conjunto enumerado que ninguém provou, e não notará um teste que passa sob
uma implementação errada. standard existe exatamente para essas duas.
ui não custa nada em trabalho sem interface: cada passo de tela é condicional à existência de uma tela.
Um passo cuja entrada está vazia custa uma linha, não uma passagem ("sem linhas de conjunto", "sem fonte
vinculante").
A junção de Coverage é escrita em checks.md em todos os perfis - a junção é o que torna uma
omissão estrutural, e isso não custa nada no momento da autoria. O que standard compra é o Verificador
recalculando a partir da autoridade sobre cada conjunto em vez de ler a tabela do autor de volta.
O perfil é um pino, não uma preferência, e ao contrário de tlc-implement, isso é imposto em vez de
solicitado: validate_verification.py falha um relatório cujo perfil difere daquele sob o qual
checks.md foi aprovado, e falha um relatório standard sem linhas de falha ou sem cobertura
recalculada, e um relatório ui sem uma seção de fontes vinculantes. Então, um passo que não foi executado
permanece distinguível de um passo que foi esquecido, que é toda a razão para declarar um
piso.
Onde o perfil parecer muito enxuto para a funcionalidade em questão, diga isso em uma linha e deixe o usuário aumentá-lo. Fazer mais do que o perfil em silêncio custa a previsibilidade que tornou a declaração válida.
Artefatos
.specs/
├── STATE.md # Registro de decisões (AD-NNN) + Snapshot de handoff
├── LESSONS.md # renderizado por scripts/lessons.py - nunca editar manualmente
├── lessons.json # de propriedade da máquina
└── features/<funcionalidade>/
├── plan.md # problema, fluxo, impacto, depois o resto da forma, depois critérios; auditoria por último
├── checks.md # afirmações + provas, junção de cobertura, política de testes, varredura
└── verification.md # relatório do Verificador
Crie cada arquivo quando sua fase produzir conteúdo. Para uma mudança de aproximadamente menos de três arquivos sem
porta unidirecional, escreva apenas checks.md com um parágrafo ## Intent (Intenção) e pule
plan.md - uma saída delimitada, não uma matriz de dimensionamento.
Entendimento e obrigações são artefatos separados
plan.md existe porque um humano precisa ser capaz de planejar e questionar antes que qualquer coisa se transforme em
uma afirmação com um seletor de teste anexado. Ler quarenta verificações para reconstruir o que está sendo construído não é
planejamento, e escrever as verificações na mesma passagem que decide a forma produz verificações que
ratificam o que já foi assumido.
Ambas as metades vivem em um arquivo porque são uma única revisão. O limite do arquivo é semântico:
deste lado, o que um humano confirma; do outro, obrigações com provas. Dividir o
plano em uma especificação e um design o cortaria em um lugar que não corresponde a nenhum dos dois,
e compraria duas paradas obrigatórias para uma funcionalidade. A ordem do arquivo é para leitura - Problema,
Fluxo, Impacto, depois o resto da forma, depois os critérios, depois as tabelas de auditoria. A ordem de escrita
não é: escreva o problema, percorra as superfícies, escreva os critérios, depois preencha a forma. Isso é o que impede
um critério de ser inventado para justificar um componente. A porta de fechamento ainda requer que todo
critério esteja em algum lugar em Flow, Relations ou Surface, ou está fora do escopo ou é uma
lacuna na forma.
A derivação para checks.md é a parte estrutural, não burocracia. Toda rota em Surface
deveria uma linha do conjunto Coverage cujos membros são seus status; toda porta em Landing
deveria uma verificação; toda entidade em Relations deve uma. Uma seção da forma sem nada apontando
para ela de checks.md está morta ou não foi comprovada, e validate_checks.py alerta sobre o caso comum.
A metade do design existe; o catálogo de componentes não. O que fez os documentos de design apodrecerem nunca foi
o diagrama, foi Propósito / Localização / Interfaces / Dependências por classe -
detalhe reversível que fica desatualizado em semanas e então engana o próximo leitor com a
autoridade de um documento escrito. Nenhum desses campos existe aqui. Cinco seções delimitadas:
| Seção | Revisa | Mantém fora |
|---|---|---|
Flow (Fluxo) | o caminho, uma linha por salto | qualquer módulo que nem existe nem é criado por uma porta - isso é posicionamento |
Impact (Impacto) | o que muda por baixo: termos e dados existentes | registros de risco |
Relations (Relações) | entidades, cardinalidade, restrições unidirecionais | colunas e tipos |
Surface (Superfície) | rota, entrada, saída, status | especificação do corpo da requisição e IDs de verificação - eles ainda não existem |
Landing (Aterrissagem) | as portas unidirecionais, com a forma literal e a alternativa rejeitada | qualquer coisa que um refator reverte |
Qual pasta, quantas classes, como o método privado se chama: o diff. Reversível, respondido pelas convenções do repositório e nunca vale um artefato. Essa é a troca deliberada, e é a única.
Uma aposta ainda em aberto quando você chega aqui - duas arquiteturas com alternativas vivas, cada uma precisando ser
avaliada em relação a este repositório - não cabe em uma linha de Landing, e uma linha é a única forma que este
artefato tem para isso. O que quer que o projeto use para resolver uma (um ADR, um RFC, um spike) vem
primeiro; então o plano registra a forma que venceu e a torna revisável.
Fluxo
Plano - o problema, depois o caminho e o que a mudança perturba, depois o resto da forma,
depois os critérios. A escrita ainda vai problema → superfícies → critérios → forma. Fatos você
consulta; decisões você pergunta - e quando pergunta, opções concretas com sua recomendação, no máximo duas
por turno. Duas enumerações fazem a descoberta, porque "considere os casos extremos" não encontra nada:
as superfícies que esta funcionalidade expõe, cada uma carregando as mesmas decisões sempre que aparece,
e as nove dimensões de requisitos implícitos. Ambas aceitam um n/a - <motivo> obrigatório,
então um espaço em branco é um item que ninguém decidiu em vez de um que não se aplica. Um artefato
que um humano lê e questiona antes de existir qualquer verificação. Processo completo, como perguntar,
regras por seção da forma, modelo e porta de fechamento: plan.md.
Verificações - derive afirmações com provas do plano, junte todo membro enumerado de conjunto a uma
verificação e registre onde cada dimensão varrida se estabeleceu. Feche com ## Handoff e a
aritmética; se a estimativa exceder o orçamento, pare para a pergunta do mecanismo antes de Construir.
Este é o artefato ao qual tudo a jusante se refere pelo número da verificação: checks.md.
Construir - sua decisão como, após a aritmética ## Handoff e, se a estimativa exceder o
orçamento, a escolha do mecanismo pelo usuário. Escreva os testes a partir das verificações,
implemente, execute cada prova, commite em pedaços coerentes. Sem lista de tarefas, sem tabelas de revisão
por tarefa. Limites, tempo de Landing, handoff e o guardrail de escopo: build.md.
Verificar - quando o último commit da funcionalidade chegar, despache um Verificador novo na mesma vez. Não pergunte. Não espere por "verificar trabalho". Procedimento, formato do relatório e re-verificação com escopo: verify.md.
Memória durável - decisões do projeto, handoff de sessão e a camada de lições: memory.md.
Scripts
Resolva <skill-dir> como o diretório contendo este SKILL.md e invoque
python3 <skill-dir>/scripts/<nome>.py. Os dados do projeto sob .specs/ permanecem relativos à
raiz do projeto; passe --root quando o diretório de trabalho atual for diferente. Uma saída diferente de zero significa PARE e corrija.
| Quando | Comando |
|---|---|
| Antes de apresentar o plano | validate_plan.py <funcionalidade> |
| Antes de começar a construir | validate_checks.py <funcionalidade> |
| Antes de cada commit | check_commit.py --message "<msg>" |
| Antes de declarar concluído | validate_verification.py <funcionalidade> |
| Na destilação | lessons.py add ... |
| Após editar um validador ou modelo | selftest.py |
validate_plan.py executa a porta de fechamento e protege a metade da forma de se tornar o que
substituiu: falha um critério sem SHALL, uma suposição sem padrão escolhido, uma linha Observable
cujo destino está em branco ou cujo n/a não tem motivo, uma linha Landing
sem forma literal ou sem alternativa rejeitada, colunas e tipos dentro de Relations, uma
rota Surface sem status e qualquer seção deixada em branco em vez de respondida com
None - <por que>. validate_checks.py é o capturador de omissões: falha uma verificação sem prova, uma
linha de cobertura cujo tamanho declarado excede os membros realmente atribuídos, uma dimensão varrida
faltando e uma linha de perfil faltando, e alerta sobre uma rota que o plano revisou mas nenhuma verificação menciona.
validate_verification.py falha um relatório PASS que não cita nenhum file:line, registra um
mutante sobrevivente, deixa um membro Unproven ou foi escrito pelo autor.
Pule um script apenas quando nenhuma ferramenta de execução de código existir; então realize as mesmas verificações lendo o artefato e diga uma vez no chat que você está no caminho degradado.
selftest.py aplica a própria disciplina deste skill às suas portas: ele muta um conjunto de fixture preenchido
uma vez por regra e requer que todo mutante seja morto, executa controles negativos provando que uma porta com escopo de
perfil não dispara abaixo de seu perfil e testa rapidamente todos os scripts enviados aqui
- um script não exercitado é onde um crash se esconde, e a porta de conclusão uma vez saiu com 0 com
...
[truncado para tradução]