Component Bug Discovery — dogfooding incident → ticket → conditional fix → signal-back

mandatory

Quando uma sessão (qualquer IA da Stack) está USANDO uma instância instalada/em-execução de um componente Koder (ex.: um `kflow`, `kdb`, `kvs` instalado; um binário/CLI/daemon Koder) enquanto faz trabalho não-relacionado, e identifica um DEFEITO nesse componente (crash, saída errada, commit perdido, arquivo corrompido, regressão, perf cliff), ela é o sensor com o **contexto forense mais rico do instante**. Esta policy torna a resposta um reflexo único: SEMPRE registrar um ticket forense; e então, segundo houver ou não **lock duro** ativo, ou corrigir agora (se cabível) ou abrir o ticket + alerta de dependência + esperar o sinal-back do fixer. Costura peças que já existiam (lock-carve-out, blocked-work-monitor, broadcast-alerts, regression-tests, backlog `blocked-by`) num fluxo só.

As IAs da Stack dogfoodam os componentes Koder o tempo todo: editam repos através de um kflow instalado, consultam um kdb rodando, commitam via kvs. Quando uma delas tropeça num defeito do próprio componente, ela está no ponto de maior contexto possível — sabe o que estava fazendo, o que quebrou, e o blast-radius imediato. Largar só um "deu erro" desperdiça isso; e ficar em silêncio deixa a próxima sessão repetir o tropeço. Esta policy converte cada IA num sensor ativo de regressão: a descoberta vira um ticket forense e, quando ela depende do fix, uma dependência rastreável com sinal-back — sem serializar à toa o que o KVS#202 já tornou seguro fazer em paralelo.

R1 — Quando dispara

Sempre que, usando uma instância instalada ou em-execução de um componente Koder (não editando o código-fonte dele — consumindo o componente), a sessão observar um comportamento que é um defeito do componente, não da própria tarefa:

  • crash / panic / exit não-zero inesperado;
  • saída errada, corrupção de dado, commit perdido, *rquivo do repo

    corrompido* índice inconsistente (típico da janela de soak do kvs);

  • regressão vs. comportamento anterior, perf cliff, deadlock, vazamento;
  • violação de invariante documentada do componente.

Não dispara para: erro de uso da própria sessão (config errada minha), bug no código que estou editando (isso é a tarefa normal), ou indisponibilidade de infra (rede/host — isso é incidente de ops, não bug de componente).

R2 — SEMPRE registrar: dois tiers de captura

Todo defeito observado é registrado — mas o peso do registro depende do tier. Exigir o ensaio forense completo (as 6 seções abaixo) para todo evento é um erro de design: a maioria dos defeitos de soak de um forge/store concorrente (kvs) são races recuperadas de alta frequência (CAS-retry, lost-update suspect que o #208 já re-mergeou, orphan reconciliado). Pedir um ensaio à mão por CAS-retry é caro demais → a sessão dropa todos em silêncio, inclusive os que importam. O conserto é separar os tiers:

R2.a — Tier 1: evento mecânico/recuperado de alta frequência → captura por telemetria

Race recuperada, lost-update suspect já re-mergeado, orphan reconciliado, retry de CAS — eventos onde o componente já se recuperou e o valor forense de cada ocorrência individual é baixo, mas o padrão agregado é o que o gate de soak precisa. Para estes, a captura é determinística pela telemetria do próprio componente (ex.: kvs wc stats linha 3a — orphaned kvs commits, #209), agregada num registro rolantenão um ticket forense à mão por ocorrência. A sessão não para para escrever ensaio; o bridge telemetria→registro (tool- agnóstico, dentro do componente — não um hook de um harness específico) faz a captura para toda IA e para o CI. Porém: se a telemetria do componente ainda não captura essa classe de evento, isso é um gap de instrumentação → a sessão registra como Tier 2 (o ticket nomeia "instrumentar X em <stats>").

R2.b — Tier 2: defeito novo / não-recuperado → ticket forense completo

Defeito novo, não-recuperado, perda real de dado, corrupção, regressão, crash, deadlock, violação de invariante — qualquer evento cujo contexto a telemetria mecânica não carrega (D11 debuggability). Aqui o ticket forense completo continua obrigatório e imediato, pela sessão descobridora, em <component>/backlog/pending/NNN-...md. Inserir ticket novo é operação collision-free — permitida mesmo sob lock duro de outra sessão (lock-carve-out.kmd R2), então nunca há razão para não registrar.

Regra de não-rebaixamento: a ausência de um stream Tier-1 automatizado não rebaixa um evento Tier-2 ao silêncio. Na dúvida sobre o tier, trate como Tier 2 (registre o ticket). "A telemetria devia ter pego" nunca é desculpa para não registrar um defeito que ela não pegou.

O ticket Tier-2 captura o contexto forense enquanto ele ainda existe (seções obrigatórias):

  • Sintoma — o que foi observado, verbatim (mensagem, hash sumido, path

    corrompido).

  • Contexto de uso — o que a sessão fazia no instante (comando, tarefa,

    componente consumido, versão/instância: kflow version, container, host).

  • Repro — passos mínimos, se já dá pra isolar; senão, o estado bruto.
  • Causa-raiz provável — a melhor hipótese da descobridora, com a evidência

    que ela vê agora (não adivinhação vazia).

  • Consequências / blast-radius — o que mais foi (ou pode ter sido) afetado:

    outras sessões, outros commits, dados a jusante.

  • Caso de regressão — o teste que falha sem o fix (regression-tests.kmd

    obriga teste por bug; capturar o caso falho agora, quando é mais barato).

Use o prefixo do componente (registries/ticket-prefixes.md) ao referir-se ao ticket cross-stack.

R3 — Decisão corrigir-ou-esperar — chaveada por LOCK DURO (não por "tem outra IA ali")

Premissa KVS#202 (lock advisory por default, kvs wc commit path-scoped com merge AST): edição concorrente no mesmo componente é segura. O gatilho da bifurcação NÃO é "outra sessão está mexendo no componente" (quase sempre está, e tudo bem) — é se há um lock exclusivity: hard ativo (migraçãorebrandrelease), per lock-carve-out.kmd R1.

R3.a — SEM lock duro ativo (caso comum) → corrija se cabível

Edição é segura. Decida pelo custo de context-switch, não pela presença de outras sessões:

  • Bug pequeno / dentro do contexto da tarefa atualcorrija agora: fix +

    teste de regressão + kvs wc commit -- <paths> (path-scoped) + push + mova o ticket para done/. Depois retome sua tarefa. Este é o caminho default do dogfooding (a descobridora é quem melhor entende o bug agora).

  • Bug grande / fora de escopo (corrigir desviaria muito da tarefa atual) →

    deixe o ticket forense (R2) detalhado em pending/ e siga sua tarefa. Não pague o context-switch caro. Outra sessão (ou um /k-go no componente) pega o ticket depois.

    • Exceção — você depende do fix para continuar: se a tarefa atual *não

      avança* sem o fix, "seguir" não é opção. Como não há lock duro, o caminho mais barato ainda é você mesma corrigir (está livre para editar). Só caia no R4 (esperar) se houver razão concreta para não corrigir (ex.: o fix exige expertise/recurso que você não tem agora).

R3.b — COM lock duro ativo → NÃO edite; vá para R4

Sob lock exclusivity: hard, editar o código-fonte do componente é proibido mesmo com autorização (lock-carve-out.kmd: buildtestdeploy/edição de src,lib,pkg,cmd,internal nunca entram em carve-out). O ticket forense (R2) já está registrado. Se você depende do fix, siga o R4. Se não depende (notou o bug mas sua tarefa avança sem ele), basta o ticket — a sessão dona do lock duro, ou a próxima, resolve.

R4 — Caminho esperar-e-sinalizar (dependo do fix e não posso/não devo corrigir)

Quando a tarefa atual depende do fix e corrigir você mesma não é o caminho (lock duro ativo, ou bug fora do seu alcance agora):

  1. Ticket forense (R2) já está em pending/.
  2. Marque sua própria tarefa/ticket com blocked-by: <COMPONENT>-NNN

    apontando para o ticket do bug (Rule 10 do /k-go; backlog.kmd). É dependência de ticket, não gated_by: (não é condição externa fora do backlog — é outro ticket que alguém vai implementar).

  3. Emita um alerta de broadcast kind: bug-dep em

    meta/context/notices/active/<slug>.md (broadcast-alerts.kmd) declarando: o componente, o ticket do bug, e que você depende dele para prosseguir. priority alta (7–8), audience: all, component: <component>. Isso faz toda sessão que tocar o componente ver que há um fix pendente bloqueando trabalho real — e dá ao fixer o handle para o sinal-back (R5).

  4. Arme o blocked-work-monitor (blocked-work-monitor.kmd: watcher

    laptop-side com TTL + ping durável koder-notify), ancorado no sinal de pronto: o ticket do bug movido para <component>/backlog/done/ OU o alerta bug-dep virando status: done.

R5 — Sinal-back do fixer

Quem pegar o ticket do bug (numa sessão de /k-go no componente, ou a própria dona do lock duro ao terminar a wave dela), ao concluir a correção — fix + teste de regressão verde + push + ticket movido para done/deve sinalizar de volta:

  • Flipar o alerta bug-dep original para status: done (1 linha no

    frontmatter). É o sinal explícito que re-aciona a descobridora.

  • Se o fixer não vê nenhum alerta bug-dep (a descobridora não emitiu, ou já

    arquivou), mover o ticket para done/ basta — o monitor da descobridora também ancora nisso. Os dois sinais são redundantes de propósito.

O fixer não precisa atualizar a instância instalada da descobridora — isso é responsabilidade dela (R6). O sinal-back diz "o código está corrigido em origin/master", não "sua instância foi atualizada".

R6 — Retomada da descobridora

Quando o monitor re-invoca a sessão (sinal de pronto disparou):

  1. Atualize a instância instalada do componente para a versão com o fix

    (rebuildreinstallupgrade — ex.: /k-reinstall <slug>, ou redeploy se for um serviço; trabalho pesado fora do laptop per heavy-work-isolation.kmd).

  2. Re-valide que o bug sumiu de fato (rode o caso de R2). Só então retome a

    tarefa original.

  3. Se o bug persistir após o upgrade → reabra o ticket (de done/ para

    in-progress/) com a nova evidência e re-arme o ciclo (R4). Não retome em cima de um fix que não pegou.

  4. Higiene: arquive o alerta bug-dep (mv para notices/archive/) — um

    alerta status: done não é exibido, mas arquivar fecha a trilha.

Worked example — commit perdido na janela de soak do kvs

Sessão A, editando engines/kodec, commita via kvs wc commit. Dois turnos depois nota que aquele commit sumiu do origin/master (regressão do soak

201).

  • R2 → abre products/dev/kvs/backlog/pending/NNN-soak-commit-loss-...md:

    sintoma (hash X ausente, era ancestral de Y), contexto (kvs wc commit -- <paths> às HH:MM, versão kvs vN), repro/estado, causa-raiz provável (race no temp-index / CAS no ref?), consequências (o trabalho de A nesse path; possíveis outros commits da janela), caso de regressão.

  • R3kvs está com lock duro? Em geral não (advisory). Se A consegue

    isolar a causa e é pequeno → corrige (R3.a) e fecha. Se é grande e A depende da correção do kvs para confiar nos próprios commits → como não há lock duro, A ainda é quem melhor entende; corrige se conseguir.

  • R4 (só se houver lock duro de release no kvs, ou se A não tem como

    diagnosticar o race agora) → blocked-by na tarefa do kodec + alerta bug-dep (priority 8) + monitor.

  • R5/R6 → o fixer do kvs fecha o ticket + flipa o alerta; A re-instala o

    kvs, re-commita o trabalho perdido do kodec, retoma.

Por que (testes)

  • T1 — Ao perceber um defeito numa instância de componente em uso, a sessão

    abre um ticket forense antes de prosseguir ou de pedir input. Verificável: o turno contém a criação do <component>/backlog/pending/NNN-...md com as seções de R2.

  • T2 — O ticket forense carrega contexto-de-uso + causa-raiz-provável +

    consequências (não só "deu erro"). Verificável: as seções existem e são específicas.

  • T3 — A decisão corrigir-vs-esperar é chaveada por lock duro, não por

    "tem outra sessão no componente". Verificável: sem lock duro, a sessão corrige (ou segue) em vez de esperar; só espera sob lock duro ou impossibilidade real.

  • T4 — Quando a sessão depende do fix e espera, ela usa blocked-by:

    (ticket-dep), não um gated_by: novo, e emite alerta kind: bug-dep + arma o monitor. Verificável: os três artefatos aparecem.

  • T5 — O fixer, ao fechar o ticket, sinaliza de volta (flip do alerta

    para status: done eou ticket → `done`). Verificável: o sinal existe.

  • T6 — A descobridora atualiza a instância e re-valida o sumiço do bug

    antes de retomar — nunca retoma em cima de um fix não-verificado. Verificável: o passo de upgrade + re-validação aparece na retomada.

  • T7 — A captura é tier-aware (R2.aR2.b): evento mecânicorecuperado de

    alta frequência é captado pela telemetria do componente (não exige ticket à mão por ocorrência), enquanto defeito novonão-recuperadoperda-de-dado exige o ticket forense Tier-2. Verificável: um soak com N races recuperadas não gera N tickets à mão (gera rollup de telemetria), mas a 1ª perda real gera o ticket Tier-2. A ausência do stream Tier-1 nunca silencia um Tier-2 (regra de não-rebaixamento).