DEV Community

suissAI
suissAI

Posted on

Descobri que faço Loop Engineering manual + Claude Dynamic Workflows

Este artigo é um thinking in public técnico. Não é uma especificação fechada, nem uma tentativa de vender uma arquitetura pronta. É o registro de como eu pego um conceito novo, debato com IA, comparo com padrões que eu já uso e tento transformar isso em DSL, grafo, agentes e behaviors reutilizáveis.

Esse print é desse vídeo https://www.youtube.com/watch?v=ij9a55_rib4

Achei interessante esse nome de Loop Engineering e ele diz que os prompts devem ser gerados dinamicamente, confesso que só comecei a testar os Agentes de Codificação essa semana, porém meu pipeline há um bom tempo é fazer um Loop de prompts onde eu debato com o ChatGTP Web a minha ideia de solução para uma funcionalidade arquitetural de um padrão de geração de sistemas via minha DSL + funções atômicas e genéricas + grafo do fluxo do payload dentro de módulo/agente onde ele define quais são as funções com suas configurações específicas e qual sequência (pode ser paralelo também). Porém eu não

Você desenha, o sistema que faz

Eu estou fazendo exatamente isso, mas não desenhando a soluçao para 1 problema, estou criando uma arquitetura altamente distribuída, ultra resiliente, auto escalável vertical e horizontalmente. Utilizando Post-Quantum ZeroTrust Passwordless, utilizo 6 linguagens diferentes e 10 bancos de dados diferentes, porém as mesmas funcionalidades eu consigo gerar 1 linguagem (backend) 1 DB (postgres). Pois é o exemplo claro do porque eu chamo de VibeCoding State-of-the-Art-Driven [Design, Development], eu otimizo ao máximo cada aspecto dessa arquitetura, fico pesquisando e debatendo com a IA até ela falar que atualmente pode ter no máximo 1 técnica/tecnologia/conceito que seja melhor, mas normalmente é algo inviável. Eu não escrevo 1 linha de código, meu único trabalho é estudar todas as coisas novas que a IA me manda, eu realmente não quero deixar 1 Agente programar TUDO para mim, pois o que eu mais gosto é de aprender todas essas coisas avançadas que há 2 meses eu nem imaginava.

Então com a minha DSL eu consigo gerar um sistema FullAgenticStack (ou só FullStack) em 6 arquiteturas diferentes pois eu crie padrões e convenções em cima de Tipos Semânticos, com um valor semântico declarado eu consigo gerar o seu comportamento semântico em diferentes camadas, com diferentes linguagens, e todas executando a mesma coisa. Então eu não peço para a IA criar 1 sistema para mim, peço para ela criar parser, converters, compilers, pois eu prefiro um código determinístico do que um diferente toda vez, faça 1 teste, crie 1 documento em Spec-Driven-Development e peça para sua IA gerar o sistema, depois entre na mesma IA com outra conta e peça EXATAMENTE a mesma coisa, mas não pode ter nada no contexto, tem que ser IDE zerada e API-KEY diferente, é altamente provável que não será o mesmo.

Acabei de chegar nesse momento onde ele diz:

O grafo é o novo nível de abstração.

E eu concordo pois com as mesmas propriedades eu já criei o graflow para 6 arquiteturas diferentes e 20 frameworks de linguagens diferentes para utilizar 3 módulo de segurança que inauguram o conceito de Semantic QuarkBehavior Type, onde ele não diz o que ou como é o valor, ele diz que comportamento aquela variável deve executar. No caso eu criei o comportamento de LinearAutoDestroy, que é o mesmo comportamento do tipo Linear, porém ele garante que o valor após utilizado é destruído da memória.

Para você elevar o nível da abstração você também precisa de reuso, quantos sistemas você fez que possui a entidade User e tem login + CRUD? Eu praticamente todos, pedindo para a IA gerar em cima de 1 documento você vai ficar gerando código diferente que deveria fazer a mesma coisa. Há 10 anos eu criei um Prova-de-Conceito da geração de um backend MVC usando apenas 1 json com as rotas e as propriedades da Entidade era 1 array com o nome das propriedades, pois desde aquela época eu tratava as propriedades como cidadãs de primeira-classe, então eu só precisava ter a pasta com o schema e o validate daquela propriedade que eu poderia reusar ela em qualquer sistema.

Criando as propriedades onde cada uma possui seu SemanticType único, pois UserId é diferente de ProductId, mesmo os 2 sendo do mesmo tipo primitivo, que toda propriedade precisa ter sua função de validate pois é ela que cria a identidade da propriedade, aposto que você nunca criou função para validar nome né? Eu pelo menos nunca tinha criado, no máximo fazia um replace para retirar caracteres que não eram letras. Sabe quem não valida Nome? O Gmail e como tem campo para Sobrenome logo ele não está pedindo um Username. Veja se você concorda comigo:

sanitize -> removeAllNonLetters -> trim 
normalize -> capitalize

PersonName -> sanitize -> normalize  -> mustHaveTwoWords -> [name, lastName] 
name -> lengthIsBetween(2, 50)
lastName -> lengthIsBetween(2, 50)

Enter fullscreen mode Exit fullscreen mode

Minha DSL é um formato que lembra class+json eliminando metade da sintaxe e é baseada em Semantic Behavior Types. Ela é compilada com Haskell + Prolog (em outro artigo eu explico isso)

Esse vídeo abriu minha mente de como eu devo usar corretamente os Agentes, é só fazer eles executarem a mesma forma que eu faço normalmente.

Como eu li sobre aqueles Dynamic Workflows do Claude e notei que já uso 5 dos 6 e sem IA quero fazer um exercício de imaginação, como estou escrevendo esse artigo enquanto eu vejo o vídeo vou pensar agora como implementar os 6 Dynamic Workflows para meus Agentes fazerem o VibeCoding como eu faço, eu devo fazer Looping VibeCoding Engineering :p

1. Classify-And-Act

Esse padrão eu uso desde o meu primeiro chatbot com IA, início de 2025, eu nem sei fazer chatbot sem isso, eu creio que deva ser o padrão mais básico e comum em sistemas com IA, né?

2. Fanout-And-Synthesize

Por padrão, não precisa declarar nada, quando chega um payload na função sub, automaticamente meu runtime executa a função forge do Semantic QuarkBehavior Type desse sub-agent/função/QuarkBehavior, ela chama a função validate interna e essa função recebe qualquer tipo de valor, pois a primeira coisa que ela faz é passar o payload em um pipeline de extração do valor primitivo, caso esse tipo não seja o aceitável ele tenta converter para seu tipo primitivo, somente se extinguirem as formas de transformar o payload para o formato desejado, todo (sub-)agent emite automaticamente o seu evento de error, para ele mesmo receber e iniciar o seu pipeline de self-healing, esse payload do error contém o payload de entrada, último estado do payload, qual valor foi invalidado, qual comportamento semântico o invalidou e o trace/span das execuções internas. Como eu não conheço nenhum programador que programa com o conceito de Intent-based Healing, eu mesmo me responsabilizo em criar e atualizar um pipeline de self-healing para essas 20 linguagens que ja tenho código gerado baseado na minha DSL.

Erros de valor são universalmente corrigidos da mesma forma, basta mudar os valores para ficar dentro do esperado, agora erros de tipos são diferentes em cada linguagem, porém conseguimos agrupar os comportamentos dos tipos das linguagens por algumas categorias.

3. Adversarial Verification

Esse é o padrão que eu provavelmente já faço de forma artesanal quando fico debatendo com o ChatGPT Web, mas ainda não tinha transformado em uma etapa formal do meu runtime.

Quando eu peço para a IA pensar em uma solução arquitetural, normalmente eu não aceito a primeira resposta. Eu começo a questionar: “mas isso é realmente seguro?”, “isso escala?”, “isso funciona em ambiente distribuído?”, “isso quebra com concorrência?”, “isso funciona offline?”, “isso continua correto se eu trocar a linguagem?”, “isso continua correto se eu trocar o banco?”, “isso respeita ZeroTrust?”, “isso respeita LinearAutoDestroy?”, “isso consegue ser provado com Haskell + Prolog?”.

Isso, na prática, já é uma forma manual de Adversarial Verification.

A diferença é que agora eu quero transformar esse debate em agentes especializados. Em vez de eu sozinho ficar tentando derrubar a solução, cada agente teria a função explícita de atacar uma parte diferente do resultado.

Por exemplo, quando minha DSL gerar um novo QuarkBehavior, ela publica o fato de que um candidato foi gerado. A partir desse fato, o fluxo pode solicitar a verificação adversarial daquele candidato:

DSL.pub("generated.candidate")

generated.candidate -> request.adversarialVerification.for.candidate
Enter fullscreen mode Exit fullscreen mode

E vários agentes podem receber esse evento de forma coreografada:

generated.candidate -> verify.candidate.with.TypeAdversaryAgent
generated.candidate -> verify.candidate.with.SecurityAdversaryAgent
generated.candidate -> verify.candidate.with.SemanticEquivalenceAdversaryAgent
generated.candidate -> verify.candidate.with.LinearUsageAdversaryAgent
generated.candidate -> verify.candidate.with.RuntimeCrashAdversaryAgent
generated.candidate -> verify.candidate.with.PayloadCorruptionAdversaryAgent
generated.candidate -> verify.candidate.with.ZeroTrustPolicyAdversaryAgent
Enter fullscreen mode Exit fullscreen mode

Cada agente não existe para “melhorar” o código. Ele existe para tentar provar que o código está errado.

O TypeAdversaryAgent tenta quebrar o comportamento usando tipos errados, objetos aninhados, valores nulos, arrays inesperados, strings vazias, valores parcialmente válidos e payloads que parecem corretos mas semanticamente não são.

O SecurityAdversaryAgent tenta encontrar vazamento de chave, replay, bypass de DPoP, quebra de mTLS, payload reaproveitado, ausência de destruição linear ou qualquer falha que viole Post-Quantum ZeroTrust Passwordless.

O SemanticEquivalenceAdversaryAgent tenta provar que a implementação em TypeScript, Zig, Haskell, Prolog, Rust ou qualquer outra linguagem não está executando exatamente o mesmo comportamento semântico.

O LinearUsageAdversaryAgent tenta descobrir se algum valor que deveria ser consumido uma única vez está sendo reutilizado, copiado, logado, cacheado ou mantido na memória depois do uso.

Isso é muito importante para mim porque meu objetivo não é gerar código “parecido” em várias linguagens. Meu objetivo é gerar o mesmo comportamento semântico em várias camadas diferentes.

Então, para mim, Adversarial Verification não é apenas revisão de código. É uma etapa de guerra contra a própria solução gerada.

O fluxo seria mais ou menos assim:

generated.candidate -> request.adversarialVerification.for.candidate

request.adversarialVerification.for.candidate
  -> fanout(TypeAdversaryAgent, SecurityAdversaryAgent, SemanticEquivalenceAdversaryAgent, LinearUsageAdversaryAgent)

TypeAdversaryAgent -> [
  Ok:pub("passed.verification.by.TypeAdversaryAgent"),
  Error:pub("found.counterexample.by.TypeAdversaryAgent")
]

SecurityAdversaryAgent -> [
  Ok:pub("passed.verification.by.SecurityAdversaryAgent"),
  Error:pub("found.securityViolation.by.SecurityAdversaryAgent")
]

SemanticEquivalenceAdversaryAgent -> [
  Ok:pub("passed.verification.by.SemanticEquivalenceAdversaryAgent"),
  Error:pub("found.semanticDrift.by.SemanticEquivalenceAdversaryAgent")
]

LinearUsageAdversaryAgent -> [
  Ok:pub("passed.verification.by.LinearUsageAdversaryAgent"),
  Error:pub("found.linearViolation.by.LinearUsageAdversaryAgent")
]
Enter fullscreen mode Exit fullscreen mode

E quando um desses agentes encontra um erro, ele não deve apenas retornar “falhou”. Ele deve retornar o contraexemplo.

Esse contraexemplo vira entrada para o meu pipeline de Intent-based Healing.

found.counterexample -> execute.selfHealingPipeline
found.securityViolation -> execute.selfHealingPipeline
found.semanticDrift -> execute.selfHealingPipeline
found.linearViolation -> execute.selfHealingPipeline
Enter fullscreen mode Exit fullscreen mode

Esse é o ponto onde o workflow deixa de ser só orquestrado e fica coreografado. O agente gerador não precisa saber quem vai verificar. Ele apenas publica o candidato. Todos os agentes interessados em provar que aquele candidato está errado se inscrevem nesse evento.

No fim, o código só deveria ser aceito quando ele sobreviver aos agentes adversários.

4. Generate-And-Filter

Esse é o padrão que mais combina com a forma como eu uso VibeCoding hoje.

Eu não quero que a IA gere um sistema inteiro diretamente. Eu quero que ela gere parser, converter, compiler, função atômica, comportamento semântico, teste, prova, grafo e convenção. Meu objetivo é que a parte criativa fique no nível da arquitetura, mas a geração final seja determinística.

Então, em vez de pedir:

Crie um sistema de login.

Eu prefiro definir:

Crie o parser da minha DSL para gerar o comportamento semântico PhoneNumber, MagicLinkToken, PasskeyChallenge, DPoPProof, LinearAutoDestroy e o grafo de execução do payload.

A partir disso, o sistema pode gerar várias versões candidatas de uma mesma coisa.

Por exemplo, para um Semantic QuarkBehavior Type, o agente poderia gerar:

- implementação mínima
- implementação strict
- implementação otimizada para performance
- implementação otimizada para segurança
- implementação com foco em prova formal
- implementação com foco em portabilidade entre linguagens
- implementação com LinearAutoDestroy explícito
- implementação com self-healing embutido
Enter fullscreen mode Exit fullscreen mode

Depois disso, entra a etapa de filtro.

O filtro não é gosto pessoal. O filtro precisa ser determinístico.

Um candidato só passa se ele:

- compila
- passa nos testes unitários
- passa nos testes de propriedade
- preserva a semântica declarada
- respeita o SemanticType
- respeita ZeroTrust
- respeita LinearAutoDestroy
- não reutiliza payload consumido
- não quebra o grafo do fluxo
- não introduz comportamento implícito
- não depende de contexto invisível
- não muda o contrato da DSL
Enter fullscreen mode Exit fullscreen mode

Esse padrão é fundamental porque IA é ótima para gerar possibilidades, mas não deve ser a autoridade final sobre o que entra no sistema.

A autoridade final deve ser o filtro.

accepted.intent -> generate.candidates

generate.candidates -> generated.candidate.1
generate.candidates -> generated.candidate.2
generate.candidates -> generated.candidate.3

generated.candidate.1 -> execute.filterPipeline
generated.candidate.2 -> execute.filterPipeline
generated.candidate.3 -> execute.filterPipeline

execute.filterPipeline -> [
  Ok:pub("accepted.candidate"),
  Error:pub("rejected.candidate")
]
Enter fullscreen mode Exit fullscreen mode

No meu caso, o filterPipeline pode ser uma composição de vários agentes:

execute.filterPipeline -> execute.compileCheck
execute.compileCheck -> execute.unitTests
execute.unitTests -> execute.propertyTests
execute.propertyTests -> execute.semanticEquivalenceCheck
execute.semanticEquivalenceCheck -> execute.securityPolicyCheck
execute.securityPolicyCheck -> execute.linearUsageCheck
execute.linearUsageCheck -> execute.benchmarkCheck
execute.benchmarkCheck -> pub("accepted.candidate")
Enter fullscreen mode Exit fullscreen mode

O mais interessante é que isso também pode ser coreografado.

O candidato não precisa passar por uma função gigante chamada validateEverything. Ele pode emitir candidate.readyForFiltering, e cada filtro se inscreve nesse evento.

ready.candidate.for.filtering -> filter.candidate.with.CompileFilterAgent
ready.candidate.for.filtering -> filter.candidate.with.TestFilterAgent
ready.candidate.for.filtering -> filter.candidate.with.SecurityFilterAgent
ready.candidate.for.filtering -> filter.candidate.with.LinearFilterAgent
ready.candidate.for.filtering -> filter.candidate.with.SemanticFilterAgent
ready.candidate.for.filtering -> filter.candidate.with.BenchmarkFilterAgent
Enter fullscreen mode Exit fullscreen mode

Cada filtro emite sua decisão.

CompileFilterAgent -> pub("passed.filter.compile")
TestFilterAgent -> pub("passed.filter.tests")
SecurityFilterAgent -> pub("passed.filter.security")
LinearFilterAgent -> pub("passed.filter.linear")
SemanticFilterAgent -> pub("passed.filter.semantic")
BenchmarkFilterAgent -> pub("passed.filter.benchmark")
Enter fullscreen mode Exit fullscreen mode

Quando todos os filtros obrigatórios passam, o Governor pode aceitar o candidato.

passed.allRequiredFilters -> accept.candidate.with.Governor
accept.candidate.with.Governor -> pub("promoted.artifact")
Enter fullscreen mode Exit fullscreen mode

Essa é a diferença entre VibeCoding comum e o que eu estou chamando de Looping VibeCoding Engineering.

No VibeCoding comum, a IA gera o código e o programador tenta fazer funcionar.

No meu caso, a IA gera candidatos, mas o runtime filtra, prova, testa, ataca, mede e só depois promove aquilo para comportamento reutilizável.

5. Tournament

Esse padrão é provavelmente o que mais pode elevar o nível dos meus agentes de codificação.

Hoje, quando eu converso com a IA, eu já faço uma espécie de torneio mental. Eu peço uma solução, depois peço outra, depois pergunto se existe uma técnica mais moderna, depois comparo com outra tecnologia, depois pergunto se aquilo escala melhor com QUIC, NATS, gRPC, WebSocket, eBPF, EventStore, Postgres, MongoDB, Qdrant, Neo4j, Redis ou qualquer outra parte da arquitetura.

Só que eu faço isso manualmente.

O Tournament seria transformar esse processo em um workflow formal.

Em vez de pedir para um agente gerar “a melhor solução”, eu posso pedir para vários agentes gerarem soluções concorrentes para o mesmo problema.

Por exemplo:

defined.problem -> open.tournament
open.tournament -> generate.candidate.with.TypeScriptAgent
open.tournament -> generate.candidate.with.ZigAgent
open.tournament -> generate.candidate.with.HaskellAgent
open.tournament -> generate.candidate.with.PrologAgent
open.tournament -> generate.candidate.with.RustAgent
Enter fullscreen mode Exit fullscreen mode

Ou então, para o mesmo problema na mesma linguagem:

defined.problem -> generate.candidate.with.minimalStrategy
defined.problem -> generate.candidate.with.strictStrategy
defined.problem -> generate.candidate.with.fastStrategy
defined.problem -> generate.candidate.with.safeStrategy
defined.problem -> generate.candidate.with.provableStrategy
defined.problem -> generate.candidate.with.distributedStrategy
Enter fullscreen mode Exit fullscreen mode

Cada candidato entra no torneio com a mesma intenção, mas com estratégias diferentes.

O vencedor não é escolhido porque “parece melhor”. Ele é escolhido por pontuação.

A pontuação pode considerar:

- compila?
- passa nos testes?
- passa nos testes de propriedade?
- preserva a semântica?
- é mais rápido?
- usa menos memória?
- aloca menos?
- é mais fácil de provar?
- é mais fácil de converter para outra linguagem?
- respeita LinearAutoDestroy?
- respeita ZeroTrust?
- gera menos eventos?
- tem melhor rastreabilidade?
- tem menor custo de self-healing?
- tem menor complexidade operacional?
- encaixa melhor no graflow?
Enter fullscreen mode Exit fullscreen mode

O torneio não precisa escolher apenas um vencedor absoluto. Ele pode escolher vencedores por categoria.

- melhor implementação para produção
- melhor implementação para prova formal
- melhor implementação para benchmark
- melhor implementação para documentação
- melhor implementação para portabilidade
- melhor implementação para segurança
Enter fullscreen mode Exit fullscreen mode

Isso faz muito sentido para minha arquitetura porque nem sempre a solução mais rápida é a solução correta. Às vezes a solução mais provável de ser provada formalmente vale mais. Às vezes a mais segura vale mais. Às vezes a mais simples é melhor porque vira padrão reutilizável para várias linguagens.

O fluxo poderia ser:

opened.tournament -> generate.candidates
generated.candidates -> request.benchmark.for.candidates
generated.candidates -> request.proof.for.candidates
generated.candidates -> request.adversarialVerification.for.candidates
generated.candidates -> request.semanticEquivalence.for.candidates

request.benchmark.for.candidates -> pub("scored.benchmark")
request.proof.for.candidates -> pub("scored.proof")
request.adversarialVerification.for.candidates -> pub("scored.adversarialVerification")
request.semanticEquivalence.for.candidates -> pub("scored.semanticEquivalence")

scored.benchmark, scored.proof, scored.adversarialVerification, scored.semanticEquivalence
  -> build.tournamentScoreboard

build.tournamentScoreboard -> select.tournamentWinner
select.tournamentWinner -> pub("selected.tournamentWinner")
Enter fullscreen mode Exit fullscreen mode

O mais importante é que o torneio transforma opinião em medição.

E isso é exatamente o que eu quero para o meu VibeCoding.

Eu quero continuar debatendo com IA, estudando conceitos novos e entendendo tecnologias avançadas, mas quando chegar a hora de transformar isso em código, eu quero que o sistema consiga competir soluções e provar qual delas é a mais adequada para aquele contexto.

Esse padrão também evita uma armadilha comum: achar que a primeira resposta boa da IA é a melhor resposta possível.

Para mim, isso é perigoso. A primeira resposta pode funcionar, mas talvez exista uma solução muito mais segura, mais simples, mais performática ou mais compatível com a minha DSL.

Então o Tournament seria o agente dizendo:

“Não vou aceitar uma resposta. Vou criar várias respostas, colocar todas para competir e deixar testes, provas, políticas e benchmarks decidirem.”

Esse é um dos pontos onde o grafo realmente vira o novo nível de abstração, porque o torneio inteiro pode ser descrito como um grafo de geração, validação, pontuação e promoção.

6. Loop-Until-Done

Esse padrão é o exemplo mais claro de como eu programo usando o conceito de Intent-based Healing.

A maioria dos sistemas trata erro como fim do fluxo.

No meu caso, erro é só mais um evento.

Quando um QuarkBehavior recebe um payload inválido, ele não deveria simplesmente retornar erro para o usuário. Ele deve emitir um evento de erro para ele mesmo, contendo todo o contexto necessário para tentar corrigir o problema.

Esse payload de erro precisa ter:

- payload original
- último estado conhecido do payload
- valor invalidado
- tipo primitivo esperado
- SemanticType esperado
- comportamento semântico que falhou
- trace/span da execução interna
- função que falhou
- tentativa de conversão já realizada
- histórico de healing
- motivo da rejeição
Enter fullscreen mode Exit fullscreen mode

A partir disso, o próprio (sub)agente pode tentar se curar.

AtomicBehavior.pub("execute.{QuarkBehavior}")

execute.{QuarkBehavior}
  -> QuarkBehavior.forge
  -> [
    Ok:pub("ended.{QuarkBehavior}.in.success"),
    Error:pub("failed.{QuarkBehavior}.at.validation")
  ]

failed.{QuarkBehavior}.at.validation
  -> selfHealingPipeline
  -> [
    Ok:pub("ended.{QuarkBehavior}.in.success"),
    Error:pub("failed.{QuarkBehavior}.at.selfHealingPipeline")
  ]

failed.{QuarkBehavior}.at.selfHealingPipeline
  -> unwrapRecursiveToPrimitive
  -> [
    Ok:pub("ended.{QuarkBehavior}.in.success"),
    Error:pub("failed.{QuarkBehavior}.at.unwrapRecursiveToPrimitive")
  ]

failed.{QuarkBehavior}.at.unwrapRecursiveToPrimitive
  -> convertTypePipeline
  -> [
    Ok:pub("ended.{QuarkBehavior}.in.success"),
    Error:pub("failed.{QuarkBehavior}.at.convertTypePipeline")
  ]

failed.{QuarkBehavior}.at.convertTypePipeline
  -> convertSemanticData
  -> [
    Ok:pub("ended.{QuarkBehavior}.in.success"),
    Error:pub("ended.{QuarkBehavior}.in.error")
  ]

AtomicBehavior.sub("ended.{QuarkBehavior}.in.success")
AtomicBehavior.sub("ended.{QuarkBehavior}.in.error")
Enter fullscreen mode Exit fullscreen mode

Esse loop não é um retry burro.

Retry burro é repetir a mesma coisa esperando um resultado diferente.

Intent-based Healing é diferente: cada nova tentativa precisa adicionar conhecimento ao estado.

Se o payload veio como objeto, o sistema tenta extrair o valor primitivo.

Se o valor primitivo veio como string, o sistema tenta converter para o tipo esperado.

Se o tipo foi convertido mas a semântica falhou, o sistema tenta corrigir o valor.

Se o valor não pode ser corrigido automaticamente, o sistema pode pedir colaboração ao usuário.

Se o usuário colabora, o sistema aprende uma nova estratégia de correção.

Se a correção for recorrente, ela vira uma função nova no pipeline de self-healing.

Então o fluxo real é mais próximo disso:

detected.error -> enrich.error
enrich.error -> request.primitiveExtraction -> [
  Ok:request.typeConversion,
  Error:pub("ended.healing.in.error")
]

request.typeConversion -> [
  Ok:request.semanticValidation,
  Error:request.semanticConversion
]

request.semanticConversion -> [
  Ok:request.semanticValidation,
  Error:request.userCollaboration
]

request.semanticValidation -> [
  Ok:pub("ended.healing.in.success"),
  Error:execute.selfHealingPipeline
]

request.userCollaboration -> [
  Ok:pub("created.learningEvent"),
  Error:pub("ended.intent.in.error")
]

created.learningEvent -> create.healingFunction
create.healingFunction -> execute.selfHealingPipeline
Enter fullscreen mode Exit fullscreen mode

Esse é o ponto onde eu digo que meu sistema não retorna erro como comportamento padrão.

Ele só deveria retornar erro quando não existe caminho seguro, válido ou cooperativo para continuar.

Se existe uma forma segura de inferir, converter, normalizar, corrigir ou pedir colaboração, então não é erro final. É uma intenção incompleta.

Por exemplo:

"gmail.con" -> corrigir para "gmail.com"
telefone sem DDD -> inferir DDD pelo contexto
"amanhã às 14h" -> converter para timestamp
nome em caixa baixa -> normalizar capitalização
payload aninhado -> extrair valor primitivo
ID externo errado -> buscar por canonical_label
grupo escrito errado -> buscar semanticamente os 3 mais próximos
Enter fullscreen mode Exit fullscreen mode

O Loop-Until-Done também explica por que eu gosto tanto de VibeCoding.

Eu faço isso comigo mesmo.

Eu tenho uma intenção arquitetural, gero uma hipótese, debato com a IA, descubro uma falha, estudo uma técnica nova, corrijo a hipótese, testo contra outro cenário, encontro outra falha, aprendo outro conceito, atualizo o padrão e continuo até a solução ficar boa o suficiente para virar DSL, parser, compiler, graflow ou Semantic QuarkBehavior Type.

Então o meu VibeCoding não é “a IA programa por mim”.

É um loop de aprendizado e refinamento arquitetural.

defined.idea -> generate.prompt -> pub("generated.answer")
generated.answer -> pub("discovered.newConcept")
discovered.newConcept -> promote.reusablePattern -> pub("promoted.reusablePattern")
Enter fullscreen mode Exit fullscreen mode

Quando esse loop vira agente, ele deixa de ser apenas conversa e passa a ser engenharia.

Por isso eu gostei tanto do nome Loop Engineering.

Eu chamaria meu caso de Looping VibeCoding Engineering porque é exatamente o que eu faço: uso IA para manter um loop contínuo entre intenção, pesquisa, arquitetura, geração, verificação, erro, healing e reuso.

Eu não quero perder esse loop, porque é nele que está a parte mais divertida: aprender técnicas e conceitos avançados todos os dias e transformar esse aprendizado em arquitetura reutilizável.

Se eu deixasse um agente programar tudo sozinho, eu talvez ganhasse velocidade, mas perderia o principal valor do processo: entender por que a solução existe, qual problema ela resolve, qual técnica ela usa, qual trade-off ela cria e como ela pode virar um padrão semântico reutilizável.

Por isso, para mim, o futuro dos agentes de codificação não é substituir meu processo.

É executar o meu processo junto comigo.

6. Loop-Until-Done

Esse padrão é o exemplo claro que como eu programo usando o conceito Intent-based Healing, pois eu não retorno erro, eu faço o seguinte:

AtomicBehavior.pub("execute.{QuarkBehavior}")

execute.{QuarkBehavior}
  -> QuarkBehavior.forge
  -> [
    Ok:pub("ended.{QuarkBehavior}.in.success"),
    Error:pub("failed.{QuarkBehavior}.at.validation")
  ]

failed.{QuarkBehavior}.at.validation
  -> execute.selfHealingPipeline
  -> [
    Ok:pub("ended.{QuarkBehavior}.in.success"),
    Error:pub("failed.{QuarkBehavior}.at.selfHealingPipeline")
  ]

failed.{QuarkBehavior}.at.selfHealingPipeline
  -> unwrap.recursive.to.primitive
  -> [
    Ok:pub("ended.{QuarkBehavior}.in.success"),
    Error:pub("failed.{QuarkBehavior}.at.unwrapRecursiveToPrimitive")
  ]

failed.{QuarkBehavior}.at.unwrapRecursiveToPrimitive
  -> convert.type.with.pipeline
  -> [
    Ok:pub("ended.{QuarkBehavior}.in.success"),
    Error:pub("failed.{QuarkBehavior}.at.convertTypePipeline")
  ]

failed.{QuarkBehavior}.at.convertTypePipeline
  -> convert.semanticData
  -> [
    Ok:pub("ended.{QuarkBehavior}.in.success"),
    Error:pub("ended.{QuarkBehavior}.in.error")
  ]

AtomicBehavior.sub("ended.{QuarkBehavior}.in.success")
AtomicBehavior.sub("ended.{QuarkBehavior}.in.error")
Enter fullscreen mode Exit fullscreen mode

Conclusão

Eu acho que nunca vou deixar de fazer o Looping VibeCoding Engenieering, pois aí eu perderia a minha alegria, aprender técnicas e conceitos mais atuais e avançados, TODO DIA (que venho pro computador), tirando o frontend, 99% da minha arquitetura foi aprendida em 2 meses, se não fosse o VibeCoding eu nunca usaria Haskell + Prolog em um Sistema Web e provavelmente nunca teria conhecido o tipo Linear e usado Zig para sistema web.

Top comments (0)