feat(sprint-1.5): rediseño visual PDF ROI + identidad InQ (Etapas 4-7)
- Header/footer compartidos con paleta InQ naranja en los 3 PDFs (Etapa 4) - Layout híbrido portrait+landscape en PDFs Actual/Automatizado: página 2 landscape para diagrama BPMN heatmap (Etapa 5) - Página 1 PDF ROI rediseñada: header denso, banner narrativo, KPI Hero con gradiente naranja→magenta, grid 2×2 de KPIs secundarios, Top 3 actividades por ahorro (Etapa 6) - Páginas 2-5 PDF ROI con identidad InQ: tabla con paleta naranja, análisis del ahorro, nota metodológica, trayectoria del ahorro acumulado con gráfico SVG nativo (Etapa 7) - 500 tests verdes (+ 34 tests nuevos del Sprint 1.5) - BACKLOG.md, TECH_DEBT.md, OBSERVATIONS.md: sistema de planificación reemplaza TODO.md Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -88,6 +88,45 @@ Caso real (InQ ROI Sprint 1.5): el primer intento fue pegar el BRIEF.md completo
|
||||
|
||||
---
|
||||
|
||||
## AP.7 — Bypass total de permisos en desarrollo local
|
||||
|
||||
**Comportamiento:** usar `--dangerously-skip-permissions` (o equivalente) rutinariamente en máquinas de desarrollo donde corren proyectos reales. El motivo declarado suele ser "evitar la fricción de aprobar cada comando".
|
||||
|
||||
**Daño concreto:**
|
||||
|
||||
1. **Pérdida de auditoría en tiempo real:** cuando un agente ejecuta una acción no intencionada (borrar archivos, modificar git history, instalar dependencias rotas), el humano lo descubre por consecuencia, no por la pausa de aprobación.
|
||||
|
||||
2. **Datos perdidos en repos en evolución:** un `rm -rf` accidental sobre el directorio equivocado puede borrar trabajo no comiteado, configuraciones locales, o assets generados que no están en git.
|
||||
|
||||
3. **Confianza falsa en el agente:** el dev se acostumbra a "todo funciona" y deja de auditar. Cuando aparece un comando raro, el reflejo de pausar ya no existe.
|
||||
|
||||
4. **Imposibilidad de saber cuándo empezó un problema:** sin puntos de control, debuggear "¿cuándo pasó X?" requiere reconstruir desde logs en vez de tener una traza de aprobaciones.
|
||||
|
||||
**Caso real (no en este equipo, observado en otros proyectos):** un desarrollador con bypass total dejó al agente refactorizar carpetas con `mv` masivos. Una iteración movió archivos a una ruta equivocada por un typo del agente en la ruta destino. Sin permisos, los `mv` se ejecutaron en cadena. Recuperar tomó 4 horas porque los archivos no estaban en stash ni en commits.
|
||||
|
||||
**Cómo detectarlo:**
|
||||
- El dev menciona "skipeo todos los permisos para ir más rápido"
|
||||
- No existe `.claude/settings.json` ni equivalente en el repo
|
||||
- El dev no sabe explicar qué hace `--dangerously-skip-permissions`
|
||||
|
||||
**Cómo evitarlo:**
|
||||
- Aplicar **Patrón D.4** (permisos versionados en `.claude/`)
|
||||
- Configurar `allow` para comandos rutinarios (que es lo que daba fricción)
|
||||
- Configurar `deny` para comandos críticos (`rm -rf` con paths absolutos, `git push --force`, `npm publish`, `git reset --hard`)
|
||||
- **Aceptar la fricción ocasional como precio de la gobernanza**
|
||||
|
||||
**Cuándo SÍ es aceptable usar bypass total:**
|
||||
- Sandboxes efímeros (contenedores Docker que se destruyen post-ejecución)
|
||||
- CI/CD donde no hay datos del dev
|
||||
- Máquinas virtuales dedicadas para experimentación
|
||||
|
||||
**Cuándo NO es aceptable:**
|
||||
- Máquina personal del dev con repos reales
|
||||
- Cualquier entorno donde haya datos no replicables
|
||||
- Cualquier entorno con credenciales o secretos
|
||||
|
||||
---
|
||||
|
||||
## Cómo agregar un anti-patrón
|
||||
|
||||
Solo se agregan anti-patrones con daño concreto observado, no especulativo. Estructura obligatoria:
|
||||
|
||||
@@ -276,6 +276,52 @@ Las decisiones arquitectónicas importantes se registran como ADR (Architectural
|
||||
|
||||
---
|
||||
|
||||
### D.4 Permisos del agente versionados en `.claude/`
|
||||
**Estado:** propuesto · **Deriva de:** Principios 4 y 5
|
||||
|
||||
Las decisiones sobre qué comandos puede ejecutar el agente sin consultar al humano se versionan en archivos de configuración del repo. Esto evita dos extremos: la fricción de aprobar cada comando manualmente, y el bypass total que abre la puerta a acciones no intencionadas.
|
||||
|
||||
**Estructura recomendada:**
|
||||
|
||||
```
|
||||
repo/
|
||||
└── .claude/
|
||||
├── settings.json ← commitable: deny patterns críticos
|
||||
└── settings.local.json ← gitignored: allow personales del dev
|
||||
```
|
||||
|
||||
**Reglas:**
|
||||
|
||||
1. **`settings.json` es del proyecto** — contiene patrones `deny` (comandos peligrosos prohibidos para todos: `rm -rf /`, `git push --force`, `npm publish`, etc.). Se comitea al repo.
|
||||
|
||||
2. **`settings.local.json` es del desarrollador** — contiene patrones `allow` personales (cada uno decide qué comandos pre-aprueba). Va en `.gitignore`. Cuando un dev nuevo arranca, **debe construir su propio** archivo siguiendo el template, no copiar el de otro.
|
||||
|
||||
3. **El equipo hereda las protecciones, no las preferencias** — los `deny` son compartidos, los `allow` son individuales.
|
||||
|
||||
**Por qué:**
|
||||
- La fricción de aprobar cada `npm install` destruye el flow de trabajo
|
||||
- Pero el bypass total elimina los puntos de control donde se detectan acciones no intencionadas
|
||||
- La gobernanza está en clasificar comandos por riesgo, no en aprobar todo o aprobar nada
|
||||
|
||||
**Indicador de aplicación correcta:**
|
||||
- En cada sesión de Claude Code, los comandos rutinarios pasan sin pedir aprobación
|
||||
- Los comandos no rutinarios siguen pidiendo aprobación (es bueno — ahí prestás atención)
|
||||
- Si un comando peligroso aparece, está bloqueado por `deny` o pide aprobación explícita
|
||||
|
||||
**Indicador de violación:**
|
||||
- El dev usa `--dangerously-skip-permissions` rutinariamente
|
||||
- El archivo `settings.json` contiene `allow` que deberían ser personales (paga la complejidad de mantenerlo sincronizado entre devs)
|
||||
- No hay archivo de configuración y cada dev aprueba todo manualmente cada vez (fricción crónica, señal de que falta este patrón)
|
||||
|
||||
**Template:** ver `methodology/TEMPLATES/CLAUDE_PERMISSIONS_TEMPLATE.md`.
|
||||
|
||||
**Relación con otros patrones:**
|
||||
- Complementa **B.4** (reglas no negociables en CLAUDE.md) — pero B.4 es sobre comportamiento del agente, D.4 es sobre permisos del sistema operativo
|
||||
- Refuerza **Principio 5** (humano director) — sin permisos configurados, el dev se vuelve operador de aprobación
|
||||
|
||||
**Casos reales que valida:**
|
||||
- InQ ROI: el director identificó fatiga de aprobación después de ~30 etapas. Configurar permisos eliminó la fricción sin perder gobernanza.
|
||||
|
||||
## Categoría E — Comunicación humano ↔ agente
|
||||
|
||||
### E.1 Separar lo validado de lo asumido
|
||||
|
||||
193
methodology/TEMPLATES/CLAUDE_PERMISSIONS_TEMPLATE.md
Normal file
193
methodology/TEMPLATES/CLAUDE_PERMISSIONS_TEMPLATE.md
Normal file
@@ -0,0 +1,193 @@
|
||||
# Template — Configuración de permisos para Claude Code
|
||||
|
||||
> Setup recomendado para `.claude/settings.json` y `.claude/settings.local.json` en cualquier proyecto.
|
||||
>
|
||||
> Implementa el **Patrón D.4** (Permisos del agente versionados).
|
||||
|
||||
---
|
||||
|
||||
## Estructura final esperada en tu repo
|
||||
|
||||
```
|
||||
repo/
|
||||
├── .claude/
|
||||
│ ├── settings.json ← versionado: solo deny patterns
|
||||
│ └── settings.local.json ← gitignored: tus allow personales
|
||||
└── .gitignore ← incluye .claude/settings.local.json
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Archivo 1: `.claude/settings.json` (versionado, compartido con el equipo)
|
||||
|
||||
Contiene **únicamente patrones `deny`**. Son las protecciones que aplicamos a todos.
|
||||
|
||||
```json
|
||||
{
|
||||
"permissions": {
|
||||
"deny": [
|
||||
"Bash(rm -rf /)",
|
||||
"Bash(rm -rf /*)",
|
||||
"Bash(rm -rf ~)",
|
||||
"Bash(rm -rf ~/*)",
|
||||
"Bash(rm -rf .git)",
|
||||
"Bash(rm -rf .git/*)",
|
||||
"Bash(git push --force *)",
|
||||
"Bash(git push -f *)",
|
||||
"Bash(git reset --hard *)",
|
||||
"Bash(git clean -fdx *)",
|
||||
"Bash(npm publish *)",
|
||||
"Bash(npm publish)"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Si tu proyecto usa otras herramientas críticas, agregá los denies correspondientes.** Ejemplos:
|
||||
|
||||
- Si usás Postgres: `"Bash(dropdb *)"`, `"Bash(psql * -c \"DROP DATABASE *\")"`
|
||||
- Si usás Docker: `"Bash(docker system prune *)"`
|
||||
- Si usás Terraform: `"Bash(terraform destroy *)"`
|
||||
- Si usás kubectl: `"Bash(kubectl delete namespace *)"`
|
||||
|
||||
---
|
||||
|
||||
## Archivo 2: `.claude/settings.local.json` (gitignored, personal)
|
||||
|
||||
Contiene **únicamente patrones `allow`**. Son los comandos que pre-aprobás para tu propio uso.
|
||||
|
||||
**Punto de partida recomendado (ajustá a tu workflow):**
|
||||
|
||||
```json
|
||||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(npm install)",
|
||||
"Bash(npm install *)",
|
||||
"Bash(npm run *)",
|
||||
"Bash(npm test)",
|
||||
"Bash(npm test *)",
|
||||
"Bash(npm run build)",
|
||||
"Bash(npm run lint)",
|
||||
"Bash(npm run dev)",
|
||||
"Bash(npm run typecheck)",
|
||||
"Bash(npx *)",
|
||||
"Bash(git add *)",
|
||||
"Bash(git commit *)",
|
||||
"Bash(git status)",
|
||||
"Bash(git diff *)",
|
||||
"Bash(git log *)",
|
||||
"Bash(git tag *)",
|
||||
"Bash(git branch *)",
|
||||
"Bash(git checkout *)",
|
||||
"Bash(git stash *)",
|
||||
"Bash(ls *)",
|
||||
"Bash(cat *)",
|
||||
"Bash(mkdir *)",
|
||||
"Bash(cp *)",
|
||||
"Bash(mv *)",
|
||||
"Bash(grep *)",
|
||||
"Bash(find *)",
|
||||
"Bash(tar *)"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Lo que NO incluí a propósito:**
|
||||
|
||||
- `Bash(rm *)` — `rm` está afuera porque incluso un `rm archivo.txt` puede ser destructivo si el archivo no estaba en git. Si querés permitirlo, ponelo explícito.
|
||||
- `Bash(git push *)` — el push interactivo te da el momento para revisar qué estás subiendo
|
||||
- `Bash(curl *)` y `Bash(wget *)` — afuera porque pueden bajar y ejecutar código de internet
|
||||
- `Bash(chmod *)` y `Bash(chown *)` — cambios de permisos quedan fuera para no automatizar accidentalmente
|
||||
|
||||
Si alguno de estos te resulta valioso para tu flujo, agregalo conscientemente.
|
||||
|
||||
---
|
||||
|
||||
## Archivo 3: `.gitignore` (asegurate que esté)
|
||||
|
||||
```gitignore
|
||||
# Claude Code local settings
|
||||
.claude/settings.local.json
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Setup inicial (paso a paso)
|
||||
|
||||
Desde la raíz del repo:
|
||||
|
||||
```bash
|
||||
# 1. Crear directorio
|
||||
mkdir -p .claude
|
||||
|
||||
# 2. Crear settings.json (versionado)
|
||||
cat > .claude/settings.json << 'EOF'
|
||||
{
|
||||
"permissions": {
|
||||
"deny": [
|
||||
"Bash(rm -rf /)",
|
||||
"Bash(rm -rf /*)",
|
||||
"Bash(rm -rf ~)",
|
||||
"Bash(rm -rf ~/*)",
|
||||
"Bash(rm -rf .git)",
|
||||
"Bash(rm -rf .git/*)",
|
||||
"Bash(git push --force *)",
|
||||
"Bash(git push -f *)",
|
||||
"Bash(git reset --hard *)",
|
||||
"Bash(git clean -fdx *)",
|
||||
"Bash(npm publish *)",
|
||||
"Bash(npm publish)"
|
||||
]
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
# 3. Crear settings.local.json (personal, gitignored)
|
||||
# [pegar contenido del Archivo 2 arriba]
|
||||
|
||||
# 4. Asegurar gitignore
|
||||
grep "settings.local.json" .gitignore || echo ".claude/settings.local.json" >> .gitignore
|
||||
|
||||
# 5. Comitear solo el compartido
|
||||
git add .claude/settings.json .gitignore
|
||||
git commit -m "chore(claude-code): configurar permisos compartidos
|
||||
|
||||
- settings.json: deny patterns críticos
|
||||
- settings.local.json en gitignore (cada dev configura sus allows)
|
||||
|
||||
Refs: methodology/PATTERNS.md D.4"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Mantenimiento del archivo personal
|
||||
|
||||
**Cuando ver que aprobás repetidamente un comando que no está en la lista:**
|
||||
1. Agregalo a `.claude/settings.local.json`
|
||||
2. Reiniciá la sesión de Claude Code
|
||||
|
||||
**Cuando un comando de la lista te causó un problema:**
|
||||
1. Sacalo de la lista
|
||||
2. Aceptá la fricción ocasional como costo de la seguridad
|
||||
|
||||
**Revisión periódica recomendada:** cada 4-6 semanas, abrir `settings.local.json` y verificar:
|
||||
- ¿Sigo usando todos los comandos de la lista?
|
||||
- ¿Hay alguno que ya no uso y conviene sacar para reducir superficie?
|
||||
|
||||
---
|
||||
|
||||
## Cuando empieces a transmitirle esto al equipo
|
||||
|
||||
Para cada miembro nuevo del equipo:
|
||||
|
||||
1. Que clone el repo (recibe `.claude/settings.json` automáticamente)
|
||||
2. Que cree su propio `.claude/settings.local.json` desde este template
|
||||
3. Que **NO copie el de otro dev** — cada uno aprueba lo que usa, no lo que el otro usa
|
||||
4. Verificar que entendió la diferencia entre `allow` (su decisión) y `deny` (decisión del equipo)
|
||||
|
||||
**Errores comunes a vigilar en miembros nuevos:**
|
||||
- Copiar el `settings.local.json` de otro y agregarse cosas "por las dudas"
|
||||
- Comitear accidentalmente el `settings.local.json` (verificar gitignore antes de su primer commit)
|
||||
- Usar `--dangerously-skip-permissions` porque "es más rápido" (ver AP.7)
|
||||
Reference in New Issue
Block a user