# Regla: Fragmentos compartidos no-routables

Esta regla es **OBLIGATORIA** para autores y mantenedores de agentes y reglas
del sistema SWL. Define un tercer tier entre reglas y skills: bloques de prompt
compartidos que se incrustan literalmente en agentes/reglas para eliminar
duplicación textual sin convertirse en componentes invocables.

---

## El problema que resuelve

Hoy cuando dos agentes necesitan repetir el mismo párrafo (protocolo HITL para
nivelRiesgo ALTO, anti-fallback silencioso, regla de paralelización, mención
de "aplica brevedad-output"), las opciones existentes son:

| Mecanismo | Problema |
|-----------|----------|
| Copiar y pegar el bloque | Drift textual: una copia se actualiza, la otra no. |
| Convertirlo en regla obligatoria | Las reglas son globales (cargadas por matchers), no se incrustan literal en un agente concreto. |
| Convertirlo en skill | Las skills se invocan dinámicamente con `Skill("nombre")` y consumen tokens; un fragmento de 6 líneas no justifica el overhead. |
| Convertirlo en agente | Los agentes son routables; un guard compartido no debe aparecer en la tabla de routing del orquestador. |

Faltaba una capa para "texto compartido que vive en el system prompt del agente,
sin overhead runtime ni routing". Esta regla la formaliza.

---

## Convención

### Ubicación y naming

| Tipo | Ubicación | Naming |
|------|-----------|--------|
| Fragmento para agentes | `agentes/_*.md` | prefijo `_`, kebab-case, **sin sufijo `-swl`** |
| Fragmento para reglas | `reglas/_fragmentos/_*.md` | prefijo `_`, kebab-case |

**Ejemplos válidos**:
- `agentes/_hitl-alto-riesgo.md`
- `agentes/_anti-fallback-silencioso.md`
- `agentes/_brevedad-output-ref.md`
- `reglas/_fragmentos/_descarga-progresiva.md`

**Ejemplos inválidos**:
- `agentes/_scope-guard-swl.md` (no usar sufijo `-swl` — no es un agente)
- `agentes/scope_guard.md` (snake_case prohibido)
- `agentes/_ScopeGuard.md` (camelCase prohibido)

### Reglas duras

1. **NO routable**: el orquestador NO incluye `agentes/_*.md` en su tabla de
   rutas. El prefijo `_` señala al loader que ese archivo es un fragmento, no
   un agente. La validación `scripts/validar-manifest.js` rechaza si un
   `agentes/_*.md` aparece en `manifiestos/modulos.json` como agente.

2. **NO invocable**: no se carga con `Skill("...")`. No tiene frontmatter
   `name`/`description` ni schema. Es texto puro Markdown.

3. **Importación declarativa via frontmatter**: el agente que usa el fragmento
   lo declara en su frontmatter:
   ```yaml
   fragmentos: [_hitl-alto-riesgo, _anti-fallback-silencioso]
   ```
   El campo `fragmentos` está definido en `schemas/agent-frontmatter.schema.json`.
   El loader (al cargar el agente) lee cada fragmento referenciado y lo concatena
   al final del system prompt.

4. **Tamaño máximo 100 líneas**: si un fragmento crece más, probablemente debe
   ser una regla obligatoria o una skill. Los fragmentos son párrafos, no
   documentos.

5. **Sin frontmatter operacional**: el archivo `_*.md` puede tener un comentario
   YAML opcional al inicio con metadata humana (autor, agentes que lo usan), pero
   NO tiene campos como `nivelRiesgo` o `permisosRed` — los hereda del agente
   que lo importa.

6. **Auditoría obligatoria**: cuando se crea un fragmento, el script
   `scripts/validar-manifest.js` verifica que el fragmento es referenciado por
   ≥2 agentes. Un fragmento usado por un solo agente no justifica su existencia
   y debe re-incrustarse en el agente.

---

## Cuándo crear un fragmento

✅ Crear cuando:
- El mismo bloque de ≥3 líneas aparece literalmente en ≥3 agentes.
- El bloque es estructural (protocolo, regla operativa) — no contenido de
  dominio variable.
- Cambiar el bloque en el futuro debe propagarse a todos los agentes.

❌ NO crear cuando:
- El texto solo aparece en 1-2 agentes (no hay ahorro real).
- El bloque ya existe como regla obligatoria (cargada por matcher).
- El comportamiento se invoca dinámicamente (eso es una skill).
- Es un párrafo de menos de 80 caracteres (no justifica el overhead de gestión).

---

## Diferencia con reglas y skills

| Capa | Cuándo carga | Cómo se usa | Ejemplo |
|------|-------------|-------------|---------|
| **Regla** (`reglas/X.md`) | Por matcher cuando se tocan ciertos archivos | Cargada al contexto global de la sesión | `reglas/seguridad.md` aplica a `*.py`, `auth/`, etc. |
| **Skill** (`habilidades/X/SKILL.md`) | Cuando un agente invoca `Skill("X")` | Carga bajo demanda, contiene instrucciones operativas | `habilidades/tdd-workflow/SKILL.md` |
| **Fragmento** (`agentes/_X.md`) | Al cargar un agente que lo declara en `fragmentos` | Se incrusta literalmente en system prompt — sin overhead runtime | `agentes/_hitl-alto-riesgo.md` |

Los fragmentos son la opción más barata: cero tokens runtime adicional, máxima
consistencia textual entre agentes que comparten un bloque.

---

## Migración desde duplicación existente

Para extraer un bloque duplicado a fragmento:

1. **Identificar**: con `Grep` confirmar que el texto aparece literal en ≥3 agentes.
2. **Crear** el archivo `agentes/_nombre.md` con el bloque en el estado más
   reciente/completo de las copias existentes.
3. **Reemplazar** en cada agente la duplicación por una referencia mínima:
   ```markdown
   <!-- fragmento: _nombre -->
   ```
   El loader sustituye este marcador por el contenido del fragmento al cargar.
4. **Declarar** en el frontmatter del agente:
   ```yaml
   fragmentos: [_nombre]
   ```
5. **Verificar** con `node scripts/validar-manifest.js` que el fragmento está
   referenciado por ≥2 agentes.
6. **Commit atómico**: `refactor(fragmentos): extraer X a _nombre — usado en N agentes`.

---

## Origen y referencias

- Patrón inspirado en `_scope-guard.md` de Bug-Bounty-Agents
  (https://github.com/anthropics/bug-bounty-agents) — convención `_` como
  shared prompt block no-routable.
- Decisión documentada en ADR-XXX (ver `.planning/adrs/`).
- Schema: `schemas/agent-frontmatter.schema.json` campo `fragmentos`.

---

## Checklist antes de crear un fragmento

- [ ] El texto aparece literal en ≥3 agentes
- [ ] El nombre sigue convención `_kebab-case.md` (sin sufijo `-swl`)
- [ ] Tamaño ≤100 líneas
- [ ] No reemplaza a una regla obligatoria existente
- [ ] No es contenido invocable dinámicamente (eso es skill)
- [ ] Cada agente que lo usa lo declara en `fragmentos: [...]`
- [ ] `scripts/validar-manifest.js` no reporta errores

## Implicaciones en scripts de auditoría/conteo de agentes

Cualquier script o hook que recorre `agentes/*.md` para contar o validar
agentes DEBE excluir fragmentos explícitamente con
`filter(f => f.endsWith('.md') && !f.startsWith('_'))`. Si no lo hace,
incluye fragmentos en el conteo y reporta cifras incorrectas o falla en la
validación de frontmatter (los fragmentos NO tienen frontmatter de agente).

Scripts y hooks SWL que aplican esta exclusión y deben mantenerla:

- `scripts/validar.js` — verifica frontmatter de agentes.
- `scripts/validar-manifest.js` — cruza `agentes/*.md` vs `modulos.json`.
- `scripts/generar-inventario.js` — cuenta agentes para INVENTARIO/SALUD.
- `hooks/validar-intent-spec.js` — regex `/\/agentes\/[^_][^/]*\.md$/`
  con clase negada para fragmentos.
- Cualquier script futuro de auditoría de agentes.

**Caso de regresión histórico**: tras crear `agentes/_intent-spec.md`
(fragmento) en sesión 2026-05-18, `scripts/generar-inventario.js` contó
61 agentes cuando real eran 60 (gate `verificar-release.js` lo detectó).
Fix: agregar el filtro al `readdirSync` del script.

**Consideración futura**: centralizar la lógica en
`scripts/lib/listar-agentes.js` con la exclusión por defecto evitaría que
el filtro se omita en scripts nuevos.
