CommunityPesquisa e Análise de Dadosgithub.com

chrislacey89/excavate

Trilha lateral invocada pelo usuário para integrar um repositório legado sem documentação, diretório docs/solutions/, arquivo de pesquisa ou decisões escritas. Extrai os últimos 12 meses do histórico do git e, quando gh está disponível, corpos de PR e threads de revisão, produzindo hotspots ranqueados, decisões recuperadas citadas e um mapa de quem consultar, e então oferece um PR com entradas em docs/solutions/. Não é para repositórios que já fazem composição, nem para julgar pessoas, nem invocado pelo modelo.

O que é excavate?

Excavate é uma habilidade especializada para Claude Code (ou agentes similares) projetada para repositórios legados sem documentação. Quando um humano digita /excavate, a ferramenta extrai os últimos 12 meses do histórico do git (e, se o GitHub CLI estiver disponível, corpos de PRs e threads de revisão) para produzir um dossiê off-tree com hotspots de código, acoplamento entre arquivos, decisões de design recuperadas e um mapa de quem perguntar sobre o quê. O dossiê segue o método de Tornhill (hotspots como probabilidades de inspeção, não veredictos) e a Regra de Fundamentação para garantir que cada citação seja copiada exatamente das saídas do git e gh, não inventada pelo modelo. Além disso, a habilidade oferece um PR opcional com entradas em docs/solutions/ no formato do pipeline /compound, permitindo que outros comandos (como /research e /write-a-prd) as encontrem. Excavate não é para repositórios que já fazem composição, não é para avaliar pessoas e nunca é auto-invocado pelo modelo.

Funciona com✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/chrislacey89/skills/tree/HEAD/excavate

Installed? Explore more Pesquisa e Análise de Dados skills: affaan-m/uspto-database, affaan-m/scholar-evaluation, affaan-m/literature-review · View all 6 →

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

O que excavate faz?

Recupere o que um repositório legado já sabe sobre si mesmo antes da primeira funcionalidade executar cega nele. A saída é um dossiê off-tree (hotspots, acoplamento, decisões recuperadas, um mapa de quem perguntar e um bloco de Cobertura dizendo o que o histórico pôde e não pôde lhe contar) mais um PR opcional com entradas docs/solutions/ no formato do /compound, para que /research, /write-a-prd e /execute os leiam através da busca por palavra-chave que eles já executam.

Duas coisas mantêm isso honesto. O método de Tornhill extrai o controle de versão como um registro comportamental: um hotspot é a interseção da frequência de mudança com a complexidade, nenhum eixo sozinho, limitado a uma janela fixa, e é uma probabilidade para inspecionar, não um veredicto para agir. E a Regra de Fundamentação (references/visual-rendering-core.md § 1) divide cada artefato: SHAs, números de PR, caminhos, contagens e justificativas citadas são copiadas da saída de git e gh, nunca redigitadas; o modelo escreve apenas a prosa ao redor delas. Uma decisão cujo "porquê" é um palpite do modelo não é recuperada, é inventada, e fica fora do repositório.

Posição de Invocação

Trilha lateral, invocada apenas pelo usuário. É acionada quando um humano digita /excavate; disable-model-invocation: true mantém sua descrição fora do contexto de qualquer outra sessão, porque é digitada uma vez por repositório, na integração, e nunca tem motivo para autoativação. Modo de planejamento, HITL (humano no loop) em toda parte; não há caminho AFK (longe do teclado), porque cada item vinculado a um commit precisa que um humano leia a citação na qual se apoia.

Envie-o como sua própria mensagem, não como a primeira mensagem de um espaço de trabalho novo. Uma habilidade oculta digitada em uma primeira mensagem à qual um host anexa um preâmbulo é lida como prosa e nunca carrega; a Posição de Invocação do /lfg registra o incidente de campo (chrislacey89/skills#383). Redigite-a como uma segunda mensagem.

O Passo 2 do /help declara o sinal para começar com ela. Não a use em um repositório que o pipeline já compõe (execute /compound lá), como uma avaliação de desempenho de alguém (veja § 5), ou como um localizador de defeitos (/qa e /triage-issue são responsáveis por isso).

Ela fica ao lado do pipeline principal e reconecta-se no /shape: a primeira funcionalidade é moldada com o dossiê e as entradas em mãos. Pode, em vez disso, passar para /request-refactor-plan quando o hotspot principal é o trabalho, ou para /qa quando o histórico mostra um cluster rotulado como "correção" que nunca foi fechado.

Regras do método

Estas são as regras que o processo abaixo operacionaliza. Cada uma aponta para sua origem; nenhuma é reafirmada em outro lugar neste arquivo.

  • Classificar por revisões, qualificar por linhas de código, nunca um eixo sozinho. Frequência sem tamanho sinaliza arquivos de configuração; tamanho sem frequência sinaliza código que foi depurado até a correção anos atrás e nunca mais tocado desde então (Tornhill, Caps. 1-4). LOC via wc -l é o proxy de complexidade: nenhum cloc é assumido, e LOC é o proxy ao qual o livro recorre por padrão.
  • Limitar a uma janela fixa. Uma contagem bruta de revisões é sem sentido sem um período de referência. Doze meses é o padrão; encurte-o para repositórios de alta velocidade. Imprima a janela real.
  • Esperar uma lei de potência e cortar no joelho. Um punhado de arquivos detém a maior parte do custo. Pare onde a curva se achata, nunca em um número redondo.
  • Uma tendência precisa de complexidade e tamanho. Deteriorando significa complexidade de indentação subindo mais rápido que LOC; Refatorado significa ambos caindo; Estável significa ambos planos (Tornhill, Caps. 5-6). LOC sozinho não pode gerar esses rótulos.
  • Filtrar arquivos não relacionados ao domínio antes do acoplamento; classificar cada acoplamento antes de relatá-lo. Arquivos de trava, manifestos, código gerado e empacotado são falsos positivos. Um teste acoplado ao seu assunto é intencional e é descartado; acoplamentos de copiar-e-colar, fronteira sem suporte e produtor-consumidor são mantidos e rotulados (Tornhill, Caps. 8-9). Histórico squashado destrói o acoplamento no nível de commit; use conjuntos de mudanças no nível de PR ou diga que a seção não está disponível.
  • Hotspots são probabilidades. Abra o arquivo antes de nomear um mecanismo e não ofereça entrada para um arquivo que você não abriu.
  • Os dados de propriedade têm quatro usos legítimos: encontrar um revisor, integração, decidir onde os testes vão e julgar se uma estrutura se encaixa na equipe. Nunca são usados para classificar ou avaliar pessoas, e são lidos através do .mailmap com bots e a importação inicial excluídos (Tornhill, Caps. 12-14).
  • A documentação existente é aspiracional. Uma alegação de ADR, README ou CHANGELOG é verificada contra a árvore atual antes de ser registrada como uma decisão vigente (Spinellis, Code Reading).
  • O primeiro movimento em um hotspot é um teste de caracterização em um ponto de estrangulamento, não uma refatoração (Feathers, Working Effectively with Legacy Code). A seção "Movimentos iniciais sugeridos" do dossiê diz isso por hotspot.
  • Um hotspot é selecionado por ser extremo, então parte de sua classificação é ruído. Regressão à média é a hipótese nula: um arquivo que lidera uma janela pode ser mediano na seguinte sem que nada seja feito a ele, e um arquivo que esfriou após uma refatoração teria esfriado de qualquer maneira (Galton; Kahneman). Classifique por persistência em ambas as metades da janela, marque cada hotspot como persistent ou single-window, e encaminhe apenas os persistentes para a lista de primeiros movimentos. A classificação é um diagnóstico, nunca um alvo; uma equipe que define metas nela obtém manipulação, não qualidade (Goodhart).
  • Registre a suposição ao lado da decisão. A justificativa é esquecida mais rápido, e suposições não registradas endurecem em números que ninguém ousa mudar (Leveson, Engineering a Safer World, Cap. 10). Cada decisão recuperada carrega a restrição que sua citação declara ("escolheu X porque Y, assumiu Z"), e se Z ainda é válido na árvore é o detector de reversão.
  • Uma entrada de decisão tem a forma de um ADR e uma linha de conformidade. Título, status, contexto, a decisão com seu porquê, consequências e como é verificada; sem o último, um registro é arqueologia em vez de governança (Richards & Ford, Fundamentals of Software Architecture, Cap. 19). A verificação aqui é a busca por grep ou verificação de caminho executada contra a árvore atual.
  • O dossiê é lido por um recém-chegado sob a maldição da expertise. Comece com um breve glossário e os hotspots do joelho, mantenha as tabelas completas atrás deles e torne a primeira tarefa de boas-vindas entender e resumir a decisão recuperada de um hotspot em vez de corrigi-la (Hermans, The Programmer's Brain).

Processo

Cada bloco cercado abaixo é executado como escrito. Cada chamada de ferramenta Bash é um shell novo, então nenhuma variável sobrevive de uma chamada para a próxima. O bloco de variáveis do Passo 0 é executado uma vez; o bloco após ele escreve cada valor resolvido em $WORK/vars.sh, e todo shell posterior, seu ou de um minerador, começa com . "$WORK/vars.sh" em vez de reexecutar o Passo 0, o que redefiniria SINCE para seu padrão e descartaria uma extensão --since ou NONDOMAIN. Um shell que pula o arquivo falha sem erro: git log --since="" não retorna commits e grep -Ev "" não imprime nada, e a saída vazia é lida como a resposta válida "sem reversões". WORK é um caminho derivado do repositório, então um novo shell o rederiva com a expressão WORK= do Passo 0 e carrega o arquivo sob ele; os mineradores recebem o caminho absoluto para vars.sh em sua instrução em vez de herdar qualquer variável. <path> é o único espaço reservado, substituído por hotspot. A semântica das flags é a documentação da própria ferramenta (git-log, git-shortlog, git-rev-parse, gh pr list); este arquivo não as parafraseia. scripts/test-documented-git-commands.sh executa cada bloco de git contra uma fixture plantada, então um bloco que deixa de ser uma invocação válida falha no CI.

0. Pré-voo

Analise os argumentos: --since <data> (padrão 12 months ago; qualquer forma que git log --since aceite) e --paths <pathspec>... (substitui o . em cada bloco abaixo). Em seguida, defina as variáveis compartilhadas:

SINCE='12 months ago'
WORK="${TMPDIR:-/tmp}/excavate-$(git rev-parse --show-toplevel | cksum | cut -d' ' -f1)"
mkdir -p -m 700 "$WORK"
START=$(git log --since="$SINCE" --no-merges --format=%cs HEAD </dev/null | tail -1)
NONDOMAIN=(':(exclude)*.lock' ':(exclude)*package-lock.json' ':(exclude)*pnpm-lock.yaml' ':(exclude)*yarn.lock' ':(exclude)*.min.*' ':(exclude)*.snap' ':(exclude)*.generated.*' ':(exclude)CHANGELOG.md' ':(exclude)*/vendor/*' ':(exclude)*/node_modules/*')
BOTS='[[]bot[]]|dependabot|renovate'
MAXFILES=30
export GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=core.quotePath GIT_CONFIG_VALUE_0=false

A exportação GIT_CONFIG_* define core.quotePath=false para cada chamada de git nesta execução (veja git-config, Environment), para que um caminho com bytes não ASCII seja impresso como ele mesmo, em vez de como uma sequência de escape entre aspas que o wc e as junções abaixo não conseguem abrir ou corresponder.

START é a primeira data de commit na janela, derivada do git em vez de date, porque date -d é exclusivo do GNU e date -v é exclusivo do BSD. NONDOMAIN é uma lista inicial: estenda-a com os caminhos gerados, empacotados, snapshot e espelhados deste repositório antes do Passo 1 (verifique git check-attr linguist-generated linguist-vendored em qualquer coisa suspeita). MAXFILES é o teto do tamanho do conjunto de mudanças acima do qual um commit é tratado como uma varredura em massa (reformatação, importação, renomeação em massa) e excluído das contagens de frequência e acoplamento. O log compartilhado no Passo 2 o aplica uma vez, quando o log é construído; nenhum bloco posterior o repete.

WORK é chaveado no caminho do nível superior do repositório, não em HEAD, porque o Passo 8 move HEAD para o branch de documentação; permanece válido entre shells e é removido no Passo 9. Se um diretório de uma execução interrompida já estiver lá, exclua-o antes do primeiro bloco do Passo 2 para que arquivos antigos não possam passar pela saída desta execução.

Persista os valores resolvidos uma vez que NONDOMAIN seja estendido (e novamente após o portão do Passo 1, se o usuário alterar a janela: carregue o arquivo, defina SINCE, reexecute a linha START= do Passo 0, então execute este bloco novamente):

{
  declare -p SINCE START NONDOMAIN BOTS MAXFILES WORK
  declare -px GIT_CONFIG_COUNT GIT_CONFIG_KEY_0 GIT_CONFIG_VALUE_0
} > "$WORK/vars.sh"

Em seguida, meça a cobertura, em um shell que comece com . "$WORK/vars.sh":

git rev-parse --is-shallow-repository
git rev-list --count --since="$SINCE" --no-merges HEAD
git log --max-parents=0 --format=%cs HEAD </dev/null | sort | head -1
git log --since="$SINCE" --no-merges --format=%s HEAD </dev/null | awk '{ t++ } /\(#[0-9]+\)$/ { s++ } END { printf "%d of %d subjects end in (#N)\n", s, t }'

As quatro linhas são: raso ou não, commits na janela, data do commit raiz (o limite raso se for raso, então diga "desconhecido" então), e a proporção de squash. Uma proporção alta de squash significa que cada commit é um PR inteiro, então o acoplamento no nível de commit já é acoplamento no nível de PR; uma proporção baixa com PRs mesclados por squash em outro lugar é o caso a observar.

Em seguida, conte os commits que aplicam uma mudança já na janela, porque um repositório que envia através de branches de release carrega a mesma mudança como um original, uma cherry-pick e uma release ou roll-up de sincronização, e cada contagem abaixo vê cada cópia como uma revisão separada:

git log --since="$SINCE" --no-merges --reverse -p --format='commit %H' HEAD -- . "${NONDOMAIN[@]}" </dev/null \
  | git patch-id --stable | awk 'seen[$(1)]++ { print $(2) }' > "$WORK/dups.txt"
wc -l < "$WORK/dups.txt" | tr -d ' '

dups.txt lista cada commit cujo ID de patch git-patch-id um commit anterior na janela já possuía, então a cópia mais antiga é aquela que não está na lista. Ele lê a mesma janela e especificação de caminho que o log compartilhado no Passo 2, então conta cópias entre os commits que a classificação lê; um branch mesclado cujas mudanças já estão na linha principal é ignorado pela simplificação de histórico do git log em ambos. A contagem vai no bloco de Cobertura, e o Passo 3 reclassifica o joelho sem esses commits. Eles são contados, não excluídos: uma mudança reaplicada ainda é trabalho que alguém fez, um roll-up pode ser o único registro das mudanças que carrega, e cada bloco posterior lê o histórico através de seu próprio git log ou git rev-list, então um filtro aplicado apenas ao log compartilhado deixaria as etapas em desacordo. Nomeie quaisquer roll-ups de release ou sincronização que você vir nos assuntos no portão de escopo; eles também não são excluídos.

Teste gh auth status e se o remoto é GitHub; registre gh: yes ou gh: no. Resolva o diretório do dossiê com bash "$SC" path research, onde SC é o caminho absoluto instalado do resolvedor agrupado desta habilidade, references/sidecar.sh; nunca calcule um caminho de sidecar você mesmo. Em SIDECAR MISS, o resolvedor sai com código 1 e imprime um comando init: mostre-o ao usuário e continue depois que ele o executar, porque criar um sidecar é um ato humano. Procure nesse diretório por um excavation-*.md anterior e por um docs/solutions/ existente; uma reexecução atualiza as entradas em vez de duplicá-las, e pontua as tags persistent do dossiê anterior contra a nova janela (quantas permaneceram quentes) para que o bloco de Cobertura carregue uma taxa de acerto para suas próprias previsões.

Se o repositório for raso, diga quanto histórico está faltando e ofereça git fetch --unshallow; nunca o execute, pois ele reescreve .git.

1. Portão de escopo (HITL)

Imprima o bloco de Cobertura exatamente como ele encabeçará o dossiê:

Window:        <START> → today (<SINCE>)
Commits:       <N> non-merge (<M> excluded as bulk > MAXFILES files)
Shallow:       yes | no
Squash ratio:  <s>/<t>
Duplicates:    <d> commits repeat an earlier commit's patch ID (counted, not excluded)
gh:            yes (<fetched> of <total> merged PRs; <closed> closed unmerged) | no
Fix labels:    <k> of <N> commits match the fix pattern (a lower bound; filled in at Step 3)
Excluded:      <NONDOMAIN list, one line>
Not visible:   closed-unmerged PRs, force-pushed or squashed history, deleted files, departed contributors

A linha Not visible não é um modelo pronto. Tudo abaixo classifica s...

Individual skills in this repo

This repo contains 4 individual skills — each has its own dedicated page.

chrislacey89/closeout

Primary pipeline tail step after /pre-merge, when a reviewed PR is ready to land and you want the workspace back to a clean base. Use to merge, switch off the worktree before removing it, prune the merged branch, pull base, and verify a clean end state. Triggers on 'close out', 'merge and clean up', 'get back to a clean main/base', 'tear down the worktree'. Not for capturing lessons (that's /compound), or closing the PRD and any other open slices and research-artifact hygiene (that's the cleanup prose in SYSTEM-OVERVIEW Step 9).

chrislacey89/compound

Primary pipeline knowledge-capture step that closes the compounding loop. Capture a durable lesson in docs/solutions/ onto the open PR before /closeout merges (the default), or post-merge when the lesson only surfaces during/after merge. Use so future /research and /write-a-prd runs improve. Not for trivial edits with no reusable project-level learning, and not for the merge/teardown itself (that's /closeout).

chrislacey89/execute

Primary pipeline execution step after /prd-to-issues or for clearly scoped implementation work. Use to build, verify, and commit a concrete slice, delegating to /tdd for backend work and behavior-heavy frontend logic when red-green-refactor will reduce risk. Not for shaping or pre-merge review.

chrislacey89/pre-merge

Primary pipeline review step after verified implementation. Use to create a PR with lineage and run architectural review before merge. Not for QA intake, planning, or implementation work.

Habilidades Relacionadas