Skip to content
Back to skills

Bus Factor Analysis

ASecurity

Detecta el Bus Factor por modulo en un repositorio git usando el algoritmo CST(change-size-ratio). Genera JSON con BF, owners, riesgo, y avisa cuando un solo dev conoce un modulo critico.

  • 50 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 27, 2026
ai-agentspythongobashvuenodegit

Works with

  • mcp

Security analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned October 4, 2026

npx -y skills add gonzalezpazmonica/savia --skill bus-factor-analysis --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Bus Factor Analysis?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Bus Factor Analysis
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/gonzalezpazmonica-bus-factor-analysis/badge)](https://www.skillsdirectory.com/skills/gonzalezpazmonica-bus-factor-analysis)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
layer: peripheral
name: bus-factor-analysis
description: >
  Detecta el Bus Factor por modulo en un repositorio git usando el algoritmo
  CST(change-size-ratio). Genera JSON con BF, owners, riesgo, y avisa cuando
  un solo dev conoce un modulo critico.
metadata:
  # --- metadata.savia.* (SE-333) ---
  savia.category: resilience
  savia.maturity: beta
  savia.context: L2
  savia.se: SE-252
  savia.summary: Skill de deteccion de riesgo de conocimiento. Analiza git history para identificar modulos con un unico conocedor y genera planes de mitigacion.
  savia.tags: "bus-factor, knowledge-graph, git-analysis, risk, resilience"
---

# Bus Factor Analysis

## Descripcion

Detecta el Bus Factor (BF) de cada modulo de un proyecto analizando el
historial git con el algoritmo CST(change-size-ratio). Un dev es owner de un
fichero si firma al menos `BF_OWNERSHIP_THRESHOLD` (0.50) de las lineas
anadidas+eliminadas (`git log --numstat --follow`). El BF de un modulo es el
menor numero de owners que cubren al menos el 50% de sus ficheros (greedy set
cover; detalle en `DOMAIN.md`):
- BF=0 → UNKNOWN: ningun fichero tiene historial atribuible (sin commits o solo bots)
- BF=1 → CRITICAL: un solo dev es owner de al menos la mitad de los ficheros
- BF=2 → HIGH: hacen falta dos devs para cubrir la mitad
- BF=3 → MEDIUM
- BF>3 → LOW

Ojo: BF=1 no significa que nadie mas haya tocado el modulo. Con 3 ficheros,
2 de Ana y 1 de Bob, el BF es 1 aunque Bob conozca su fichero.

Identidad de autor: el email tras aplicar `.mailmap` del repo (`%aE`); dos
emails de la misma persona cuentan como uno solo si el `.mailmap` los une.
Se excluyen bots: `[bot]`, `dependabot`, `renovate`, `github-actions`,
`snyk-bot`, `automated` (buscados en nombre y email, asi que una persona con
uno de esos terminos en el nombre tambien se excluye), `action@github.com`, y
partes locales `ci@`, `noreply@` o `no-reply@` como segmento propio (al inicio
o tras `-`, `_`, `.`, `+`: `gitlab-ci@`, `build-noreply@`). `marci@`,
`marcinoreply@` y `*@users.noreply.github.com` son humanos y SI cuentan.

## Cuando usar

- Pre-sprint si hay devs de vacaciones o baja
- Tras la salida de cualquier miembro del equipo
- Mensualmente como revision de riesgo organizativo
- Cuando un nuevo dev se incorpora (para generar su plan de onboarding)
- Cuando se detecta siloizacion de conocimiento

## Rutas criticas

- Motor Python:   `scripts/bus-factor-scan.py`
- Orquestador:    `scripts/bus-factor-scan.sh`
- Cupulas:        `scripts/context-dome-generate.sh`
- Distribucion:   `scripts/bus-factor-distribute.sh`
- Informe:        `scripts/bus-factor-report.sh`
- Hook PostWrite: `.claude/hooks/bus-factor-warn.sh`
- Protocolo:      `docs/rules/domain/bus-factor-protocol.md`
- DOMAIN:         `.claude/skills/bus-factor-analysis/DOMAIN.md`

## Flujo de uso

```bash
# 1. Escanear proyecto
bash scripts/bus-factor-scan.sh --project <path>

# 2. Generar cupulas para modulos criticos
bash scripts/context-dome-generate.sh --project <path> --min-risk HIGH

# 3. Plan de distribucion para un dev
bash scripts/bus-factor-distribute.sh --project <path> --target <dev-email>

# 4. Informe ejecutivo
bash scripts/bus-factor-report.sh --project <path> --format markdown
```

## Output esperado

JSON en `output/bus-factor/<proyecto>-<YYYYMMDD>T<HHMMSS>Z.json` con estructura:
```json
{
  "generated_at": "2026-10-03T05:17:17Z",
  "project": "...",
  "modules": [{"name": "...", "bus_factor": 1, "risk_level": "CRITICAL", "owners": [...], "files": [...], "warnings": []}],
  "summary": {"total_modules": 11, "critical": 2, "high": 3, "medium": 1, "low": 4, "unknown": 1},
  "warnings": []
}
```

Rutas de fichero y nombres de modulo son relativos al directorio escaneado
(se puede escanear un subdirectorio de un repo). Rutas con espacios o no
ASCII se tratan literalmente.

`bus-factor-report.sh` y `bus-factor-distribute.sh` solo leen el scan de ese
proyecto: `<proyecto>.json` o `<proyecto>-<timestamp>.json` en
`BF_OUTPUT_DIR` (el mas reciente). Nunca caen al scan de otro proyecto. Un
scan guardado con `scan.sh --output` y otro nombre no se encuentra: usa el
nombre por defecto o `--output "$BF_OUTPUT_DIR/<proyecto>.json"`.

### Codigos de salida

| Script | 0 | 1 | 2 |
|--------|---|---|---|
| `bus-factor-scan.py` | JSON emitido (tambien repo sin commits: `no_tracked_files`) | directorio inexistente o no es repo git | — |
| `bus-factor-scan.sh` | scan escrito | argumentos invalidos, `--format` distinto de `json`, o fallo del motor | — |
| `bus-factor-report.sh` / `-distribute.sh` | informe emitido | argumentos invalidos o no hay scan del proyecto | scan JSON ilegible |

## Configuracion

Solo variables de entorno (no hay fichero de configuracion por proyecto):

| Variable | Default | Descripcion |
|----------|---------|-------------|
| `BF_OWNERSHIP_THRESHOLD` | `0.50` | Score minimo para ser owner |
| `BF_RISK_CRITICAL` | `1` | 1 <= BF <= N es CRITICAL |
| `BF_RISK_HIGH` | `2` | BF <= N es HIGH |
| `BF_RISK_MEDIUM` | `3` | BF <= N es MEDIUM |
| `BF_MAX_HISTORY_DEPTH` | `0` | Commits maximos por fichero (0 = todo el historial) |
| `BF_MODULE_DEPTH` | `2` | Profundidad de agrupacion |
| `BF_EXCLUDE_PATTERNS` | `vendor/,node_modules/,*.lock` | Patrones a excluir |
| `BF_EXCLUDE_GENERATED_PATTERNS` | `*.pb.go,*_generated*,*auto_generated*,*.min.js,*.min.css` | Ficheros generados a excluir |
| `BF_EXCLUDE_BINARY` | `1` | Excluir ficheros marcados binarios en `.gitattributes` |
| `BF_OUTPUT_DIR` | `output/bus-factor/` | Directorio de salida |

## Limitaciones

1. Se miden lineas cambiadas (`git log --numstat`), no comprension real
2. Los commits de merge no suman cambios (su autor no se vuelve owner); un
   squash-merge atribuye todo el trabajo a quien lo firma
3. Sin `.mailmap`, la misma persona con dos emails cuenta como dos devs
4. Los owners se identifican por email: el JSON y los informes contienen
   datos personales. Se quedan en `output/` (gitignored); no pegarlos en
   issues, PRs ni canales publicos
5. No detecta conocimiento organizativo (ver org-stakeholder-mapper)
6. Human decides: el script solo genera findings, no actua

## Integraciones

- `context-dome` skill: genera CONTEXT_DOME.md con conocimiento tacito
- `human-code-map` skill: usa el plan de distribucion para onboarding
- `codebase-memory-mcp`: enriquece nodos File con bus_factor property

Files in this skill

  • DOMAIN.md4 KB
  • SKILL.md3.4 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…