Referência de métricas e códigos
Folha de consulta densa para tudo que o harness-score reporta: pontuações, escopos, níveis, dimensões, IDs de check, chaves de configuração, flags da CLI, inputs da Action e campos JSON. Receitas de remediação estão no capítulo 8 — Medir e melhorar.
Pontuações: maturity vs effective
| Código | O que inclui | Usado para |
|---|---|---|
| maturity | Somente arquivos do repositório (scopes: repo) | Gate padrão de CI, badge, --min-level, maturidade oficial do time |
| effective | Repo ∪ escopos globais/extras configurados | Localmente: “o que o agente vê nesta máquina” quando harness user/system está habilitado |
Quando nenhum escopo extra está configurado, effective iguala maturity (mesmo nível, pontuação e checks). O relatório sempre inclui ambos os blocos para JSON estável.
Defina qual pontuação faz gate no CI com gate na config, --gate ou o input gate da Action (maturity por padrão).
Escopos
| Escopo | Significado | O que é escaneado |
|---|---|---|
repo | Sempre ativo | O diretório passado ao harness-score (padrão .). Quando a raiz do scan é um repositório plugin Claude Code ou Cursor (.claude-plugin/plugin.json ou .cursor-plugin/plugin.json na raiz), skills/, commands/, agents/ e hooks/hooks.json default contam como .claude/... / .cursor/.... |
user | Opt-in | Caminhos allowlisted mapeados para formas repo-relative: ~/.cursor/*, ~/.claude/*, plugins Claude Code user-scoped em ~/.claude/plugins/installed_plugins.json, ~/.codeium/windsurf/* (alias Windsurf), ~/Documents/Cline/Rules → .clinerules/, ~/.continue/{rules,prompts}, ~/.agents/*, ~/.zed/commands, ~/.config/opencode/agents, etc. Ver multi-harness — user scope por ferramenta. Não inclui: Copilot global (só repo), regras inline do Continue em config.yaml, User Rules do Cursor só na UI, cache de plugins Cursor no usuário (v1). |
system | Opt-in | Reservado para instalações validadas em nível de sistema (mínimo na v1) |
extraRoots | Opt-in | Diretórios adicionais (relativos ou absolutos) cuja árvore espelha o layout do harness — ex.: checkout compartilhado de harness do time |
Arquivos do projeto vencem caminhos de overlay em conflito (mesmo caminho relativo).
Não escaneado: Cursor User Rules armazenadas só na UI do IDE (não em disco), varreduras arbitrárias do home directory, ou conteúdo de segredos em strings de evidência.
Níveis (L0–L4)
Nomes oficiais de nível aplicam-se à maturity, salvo se você definir gate: effective.
| Nível | Nome | Requisitos (todos os níveis anteriores +) |
|---|---|---|
| L0 | Unharnessed | — |
| L1 | Documented | context ≥ 40% |
| L2 | Guided | context ≥ 60%; skills ≥ 30% ou hooks ≥ 30%; hygiene ≥ 50% |
| L3 | Sensing | sensors ≥ 60%; ci ≥ 50% |
| L4 | Self-correcting | hooks ≥ 70%; total ≥ 80% |
Narrativa completa: O modelo de maturidade.
Dimensões
| ID | Título | Pts máx | Mede |
|---|---|---|---|
context | Context & Guides | 20 | AGENTS.md, rules com escopo, README |
skills | Skills & Commands | 17 | Skills, commands/workflows, subagents |
hooks | Hooks & Guardrails | 14 | Configurações de hooks do Cursor, Claude Code e Devin |
sensors | Sensors & Feedback | 20 | Testes, linter, tipos, formatter |
ci | CI Feedback | 14 | Pipeline, pre-commit |
hygiene | Hygiene & Safety | 23 | .gitignore, segredos, lockfile, licença, higiene MCP |
Total: 108 pontos quando todo check se aplica. O score.max de um scan fica menor quando um check não se aplica (checks[].applicable é false) ou está em "off".
Catálogo de checks
IDs estáveis — vinculados à remediação em Medir e melhorar.
Context & Guides
| ID | Pts | Analisa exatamente | Remediação |
|---|---|---|---|
| CTX-01 | 4 | Root AGENTS.md, CLAUDE.md, ou GEMINI.md, ou .claude/CLAUDE.md / .claude/AGENTS.md | ctx-01 |
| CTX-02 | 3 | Arquivo de contexto tem ≥20 linhas significativas e ≥2 headings | ctx-02 |
| CTX-03 | 4 | Pelo menos um arquivo de rule com escopo (qualquer ferramenta), .claude/rules/**/*.md, ou contexto aninhado em subdiretório de código | ctx-03 |
| CTX-04 | 3 | Toda rule declara metadados de ativação no frontmatter | ctx-04 |
| CTX-05 | 2 | Nem toda rule é always-on genérica | ctx-05 |
| CTX-06 | 2 | Nenhum arquivo de rule único excede 500 linhas | ctx-06 |
| CTX-07 | 1 | README.md na raiz do repositório | ctx-07 |
| CTX-08 | 1 | Sem .cursorrules legado sem rules modernas com escopo | ctx-08 |
Skills & Commands
| ID | Pts | Analisa exatamente | Remediação |
|---|---|---|---|
| SKL-01 | 4 | Pelo menos um SKILL.md em diretório de skills reconhecido | skl-01 |
| SKL-02 | 3 | Toda skill tem name: e description: no frontmatter | skl-02 |
| SKL-03 | 3 | Arquivos command/workflow existem para qualquer ferramenta suportada | skl-03 |
| SKL-04 | 2 | Descrições de skill têm ≥40 caracteres | skl-04 |
| AGT-01 | 3 | Pelo menos um arquivo markdown de subagent | agt-01 |
| AGT-02 | 2 | Todo subagent tem frontmatter name: e description: | agt-02 |
Hooks & Guardrails
| ID | Pts | Analisa exatamente | Remediação |
|---|---|---|---|
| HKS-01 | 4 | Config de hooks do Cursor, Claude Code ou Devin existe e parseia como JSON | hks-01 |
| HKS-02 | 2 | Eventos e handlers tipados são estruturalmente válidos; evento válido desconhecido gera warning | hks-02 |
| HKS-03 | 4 | Hook classe gate registrado (shell/MCP/read/tool gate) | hks-03 |
| HKS-04 | 2 | Hook classe feedback registrado (post-edit/tool) | hks-04 |
| HKS-05 | 2 | Todo caminho local em executáveis e args existe; handlers sem comando não se aplicam | hks-05 |
Sensors & Feedback
| ID | Pts | Analisa exatamente | Remediação |
|---|---|---|---|
| SNS-01 | 6 | Test runner configurado (script em package.json, pytest, phpunit.xml, pest, go test, node --test, …) | sns-01 |
| SNS-02 | 5 | Linter configurado (eslint, biome, ruff, phpcs, rector, golangci-lint, …) | sns-02 |
| SNS-03 | 4 | Type checking configurado (tsconfig, mypy, pyright, ty, phpstan, psalm, …) | sns-03 |
| SNS-04 | 3 | Formatter configurado (prettier, black, pint, php-cs-fixer, gofmt, …) | sns-04 |
| SNS-05 | 2 | Pelo menos um arquivo de teste existe na árvore | sns-05 |
CI Feedback
| ID | Pts | Analisa exatamente | Remediação |
|---|---|---|---|
| CI-01 | 4 | Arquivo de pipeline CI presente (GitHub Actions, GitLab CI, …) | ci-01 |
| CI-02 | 4 | CI executa comandos de teste (phpunit, pest, …; resolve scripts Composer referenciados; ignora rótulos de etapas) | ci-02 |
| CI-03 | 3 | CI executa comandos de lint ou typecheck (phpstan, pint, phpcs, …; resolve scripts Composer referenciados; ignora rótulos de etapas) | ci-03 |
| CI-04 | 3 | Ferramenta pre-commit ou git hook instalada | ci-04 |
Hygiene & Safety
| ID | Pts | Analisa exatamente | Remediação |
|---|---|---|---|
| HYG-01 | 2 | .gitignore presente | hyg-01 |
| HYG-02 | 3 | .gitignore cobre arquivos de ambiente | hyg-02 |
| HYG-03 | 4 | Sem arquivos .env desprotegidos (sem padrão .env.example) | hyg-03 |
| HYG-04 | 4 | Configs JSON de MCP sem padrões inline de credencial | hyg-04 |
| HYG-05 | 2 | Arquivo LICENSE presente | hyg-05 |
| HYG-06 | 2 | Sem assinaturas tipo credencial em markdown/JSON de harness | hyg-06 |
| HYG-07 | 3 | Lockfile de dependências commitado | hyg-07 |
| HYG-08 | 3 | Configs MCP usam interpolação de env para segredos | hyg-08 |
Arquivo de configuração (.harness-score.json)
JSON opcional na raiz do scan (schema estrito — chaves desconhecidas geram erro):
{
"scan": {
"includePaths": ["build/ci"]
},
"scopes": {
"user": false,
"system": false
},
"extraRoots": [
{ "id": "team-shared", "path": "../shared-harness" }
],
"gate": "maturity",
"extends": ["no-hooks"],
"rules": {
"HYG-05": "off"
}
}| Chave | Tipo | Padrão | Significado |
|---|---|---|---|
scopes.user | boolean | false | Incluir overlay de harness em nível de usuário |
scopes.system | boolean | false | Incluir overlay em nível de sistema |
extraRoots | { id, path }[] | [] | Árvores extras de harness mescladas no effective |
scan.includePaths | string[] | [] | Arquivos/diretórios exatos, relativos à raiz, a incluir em pastas normalmente ignoradas; sem curingas |
gate | "maturity" | "effective" | "maturity" | Qual pontuação o --min-level usa |
extends | string[] | [] | Presets nomeados a aplicar (veja abaixo) |
rules | Record<checkId, severity> | {} | Override de severidade por check, aplicado depois de cada preset em extends |
Precedência: flags da CLI → inputs da Action → arquivo de config → padrões. scan.includePaths, extends e rules são configurados no arquivo; use --config <path> para apontar para um .harness-score.json que os defina. A GitHub Action lê o mesmo arquivo.
scan.includePaths aceita caminhos exatos relativos à raiz do repositório, com separadores /. Um caminho pode indicar um arquivo ou diretório; diretórios selecionados incluem os descendentes recursivamente. Caminhos absolutos, .. e curingas não são aceitos. Caminhos inexistentes são ignorados. As exclusões padrão continuam valendo fora dos caminhos selecionados, e a lista efetiva aparece nos relatórios e é comparada com baselines.
Personalização por equipe: extends e rules
O vocabulário é emprestado diretamente do ESLint, porque é um vocabulário que a maioria das equipes já conhece:
rulessobrescreve a severidade de um check específico por ID:"HYG-05": "off". A severidade é"off"ou"error"nesta versão —"error"é o padrão implícito de todo check, e"off"remove o check do numerador e do denominador da pontuação da sua dimensão (é excluído estruturalmente, nunca contado como falha)."warn"é um valor reconhecido mas deliberadamente rejeitado hoje com um erro claro de "ainda não suportado" — reservado para um modo futuro, consultivo e não-bloqueante.extendsaplica um preset nomeado e curado pelos mantenedores — um pacote versionado e revisado via PR de overrides derules, não uma isenção livre por repositório. Isso preserva a mesma governança que já protege o catálogo de checks: propor um preset novo passa por revisão (veja CONTRIBUTING.md), não é um opt-out local silencioso. Presets emextendssão aplicados na ordem do array, e qualquer entrada explícita emrulessempre prevalece sobre um preset.
Todo check excluído por extends/rules é sempre divulgado — na saída do terminal (linha Preset: ...), no relatório Markdown (linha **Preset:** e status ➖ na tabela de checks) e no campo preset do --json — nunca escondido silenciosamente atrás de uma flag.
Uma exceção, proposital: HYG-03, HYG-04 e HYG-06 — os checks que detectam credenciais efetivamente vazadas ou expostas — nunca podem ser definidos como "off", nem via rules nem via preset. Todo o resto nesse formato de config se apoia em divulgação e revisão de PR pra manter a integridade; esses três são o único ponto que não é negociável.
Presets nativos
| Preset | Efeito | Por quê |
|---|---|---|
no-hooks | Define HKS-01–HKS-05 (toda a dimensão Hooks & Guardrails, 14 dos 108 pontos) como "off" | Para ambientes onde a execução de scripts de hook local é vedada por política — dev containers travados, orgs reguladas, runners compartilhados sem permissão de instalar hooks. O guardrail nesses casos é aplicado só via CI. |
Excluir uma dimensão inteira tem uma consequência honesta que vale saber de antemão: como L4 · Self-correcting é definido por hooks de guardrail em runtime (veja o Modelo de Maturidade), um repositório sob no-hooks nunca alcança L4 — o nível fica capped (limitado), não "reprovado". report.level.capped é true e report.level.capReason explica o motivo; toda outra dimensão continua com a pontuação intacta. Isso é o scanner sendo honesto sobre o que "self-correcting" significa, não uma penalidade por excluir hooks.
Flags da CLI (configuração do scan)
A descoberta de maturity no repositório não possui limite de profundidade em produção. Ela inclui arquivos rastreados, não rastreados e ignorados depois de pular diretórios conhecidos de dependências e artefatos gerados. file-count-limit representa um fusível emergencial de 1.000.000 de arquivos para o repositório; overlays limitados de user e extra roots ainda podem reportar depth-limit. Um caminho descoberto que não possa ser inspecionado quando solicitado por um check reporta unreadable-path; conteúdos acima de 512 KiB, ignorados intencionalmente, não reportam esse motivo. Symlinks internos são seguidos e deduplicados, enquanto um alvo fora da raiz reporta outside-root-symlink e não é percorrido nem lido.
| Flag | Significado |
|---|---|
--config <file> | Carregar config de caminho específico |
--scope user | Habilitar escopo user (separados por vírgula: user, system) |
--gate maturity|effective | Pontuação usada para --min-level |
--min-level <0-4> | Exit 1 quando a pontuação gated completa está abaixo do nível; snapshot selecionado pelo gate incompleto retorna exit 2 |
--json | Relatório completo incluindo scopes, gate, effective e verdicts |
Inputs da GitHub Action
| Input | Padrão | Significado |
|---|---|---|
include-user-harness | false | Passa --scope user |
include-system-harness | false | Passa --scope system |
gate | maturity | Passa --gate |
config | '' | Passa --config quando definido |
min-level | 0 | Falha quando pontuação gated está abaixo do nível |
Outputs: level, level-name, percent (maturity); effective-level, effective-percent. A Action publica outputs, badge e relatório de maturity somente quando maturity está completo, e outputs de effective somente quando effective está completo. Se apenas effective estiver incompleto, gate: maturity pode passar com um aviso; gate: effective retorna exit 2. Maturity incompleto não publica outputs de maturity, badge, relatório ou comentário na PR.
Campos JSON do relatório (estáveis)
| Campo | Descrição |
|---|---|
root | Raiz absoluta do scan |
scopes.maturity | Sempre ["repo"] |
scopes.effective | ex.: ["repo"], ["repo","user"] |
gate | "maturity" ou "effective" |
resolvedRoots | Lista opcional de { scope, absPath } para overlays |
level, score, dimensions, checks | Snapshot de maturity |
effective | Mesma forma: { level, score, dimensions, checks, detectedHarnesses } |
detectedHarnesses | Ferramentas vistas no repo (informativo) |
verdicts.maturity, verdicts.effective | Status de completude e motivos determinísticos de cada snapshot: complete ou incomplete |
verdicts.*.reasons[] | file-count-limit, depth-limit, unreadable-directory, unreadable-path ou outside-root-symlink, com path e limit opcionais |
truncated | Alias de compatibilidade; true quando o snapshot de maturity ou effective está incompleto por qualquer motivo |
preset | { extends, rules, resolved } — personalização de equipe efetivamente aplicada; resolved só lista checks cuja severidade difere do padrão |
level.capped, level.capReason | capped é true quando um requisito bloqueante do próximo nível nunca pode ser satisfeito sob a config atual (ex.: dimensão excluída por preset); capReason explica o motivo |
dimensions[].applicable | false quando nenhum check daquela dimensão entra na pontuação: todo check está "off" e/ou checks[].applicable é false |
checks[].applicable | false quando o check não se aplica a este repositório (HYG-05 com license de código fechado, HYG-08 sem config MCP). Excluído do numerador e do denominador. O padrão é true. Ausente em relatórios antigos, o que significa aplicável |
checks[].severity | "off" | "warn" | "error" — a severidade resolvida usada por este scan para aquele check |
checks[].warnings | Diagnósticos opcionais e não fatais { code, message, source? }; terminal e Markdown os exibem sem alterar pontos |
level, score, dimensões e checks continuam presentes para diagnóstico, mas são provisórios quando o veredito correspondente é incomplete. Terminal e Markdown identificam o snapshot indisponível. O badge sempre representa maturity e usa incomplete, nunca L0-L4, quando maturity está incompleto. Relatórios antigos sem verdicts são completos quando truncated é false e incompletos quando é true.
--diff compara campos de maturity por padrão (top-level level / score / checks) e rejeita baseline ou resultado atual com maturity incompleto. Effective incompleto não bloqueia um diff de maturity. Um check que passa de aplicável para não aplicável (ou o inverso) é um delta próprio (became-applicable / became-not-applicable), separado de newly passing ou newly failing.