# 0087 — Capability Discovery Acceleration

**Status:** open
**Created:** 2026-05-14
**Related:** 0085 (telemetry), 0086 (delegation + capability groups)

## Problema

Crear funciones para reutilizar = bueno largo plazo, pero introduce un **coste de descubrimiento** cada sesion: Claude tiene que FTS-buscar antes de usar. Si la busqueda falla o es mediocre, Claude reinventa inline ("violation: reinvent_inline"). En la sesion del 2026-05-13/14 Claude reinvento taskkill+cp+start 5 veces seguidas pese a que `deploy_cpp_exe_to_windows` ya existia.

Objetivo: que **conocer las capacidades sea gratis o casi gratis** para Claude.

## Modelo de capas

Cinco capas escalonadas por coste de lookup. Cada una cubre un slice de casos:

| Capa | Coste lookup | Cobertura | Mecanismo |
|---|---|---|---|
| 1 | 0 (contexto base) | Top 20 funciones mas usadas + funciones creadas ultimos 7d | Bloque auto-generado en `CLAUDE.md` |
| 2 | 0 (cada turno) | Funciones recien creadas + violations recientes | Hook `UserPromptSubmit` injecta linea `FRESH:` / `TOP:` |
| 3 | 0 (mid-flight) | Patrones inline que matchean funcion existente | Hook `PreToolUse` con fuzzy FTS5 |
| 4 | 1 read on demand | Cualquier dominio especifico | `docs/capabilities/<group>.md` cargado solo si tarea matchea |
| 5 | 0 (persistente) | Insights cross-session | `MEMORY.md` linea por capacidad clave |

## Piezas (7)

| # | Pieza | Lang/Tipo | Aprox LOC | Tanda |
|---|---|---|---|---|
| 1 | `fn doctor capabilities --emit-claude-md` — top 20 + fresh 7d | Go subcommand | 80 | A |
| 2 | Hook `UserPromptSubmit` → linea `FRESH:` + `TOP:` | bash | 40 | B |
| 3 | `fn_match` binario fuzzy FTS5 sobre functions (input: command, output: top-N matches) | Go binary | 120 | A |
| 4 | Hook `PreToolUse` → consume `fn_match`, inyecta `USE:` hint si confidence alta | bash | 60 | B |
| 5 | `ids_naming.md` endurecer + validator en `fn_create_function` | Go + rules | 50 | A |
| 6 | `/fn_claude` post-creation auto-append `[[fn_id]] — purpose` a `MEMORY.md` | bash skill | 30 | C |
| 7 | Excepcion explicita en `registry_calls.md`: hooks pueden leer `registry.db` directo | rules | — | A |

### Fuzzy matching (pieza 3 + 4)

`fn_match`:
- **Input:** command string + optional tool context (Bash / Edit / heredoc).
- **Pipeline:**
  1. Tokenizar comando: split en palabras, ignora flags (`-v`, `/F`), conserva tokens significativos.
  2. Query FTS5 sobre `functions_fts MATCH 'tok1 OR tok2 OR ...'` ordenado por `bm25()`.
  3. Re-score con weights: `name` match peso x3, `tags` peso x2, `description` peso x1.
  4. Threshold dinamico: `top.score / second.score > 1.5` → confidence alta.
- **Output JSON:** `[{id, score, signature, snippet}, ...]` top 3.
- **Latencia objetivo:** < 50ms (hook PreToolUse no puede bloquear).

Hook `PreToolUse`:
- Captura tool + payload.
- Llama `fn_match` con timeout 200ms (no bloquea si tarda).
- Si confidence alta → inyecta `<system-reminder>FUZZY-MATCH: USE \`./fn run <id>\` instead. Signature: <sig>.</system-reminder>` en stderr (Claude lo lee).
- Si confidence baja → silencio.

### Excepcion hooks (pieza 7)

`.claude/rules/registry_calls.md` actualmente dice "NUNCA sqlite3 registry.db directo" pero esa regla apunta al AGENTE. Los hooks son lectores externos del proceso de Claude — necesitan acceso directo y rapido a FTS5 sin pasar por MCP (que requiere tool invocation por Claude). Anadir clausula:

> **Hooks (PreToolUse/PostToolUse/UserPromptSubmit) pueden leer `registry.db` directo via `sqlite3` o binario Go con read-only conn.** No estan sujetos a la regla MCP-first porque no son acciones del agente, son inspeccion automatizada del entorno. Excepcion: SOLO lectura. NUNCA escritura desde hooks.

## Plan de tandas (paralelizable)

### Tanda A — cero dependencias, lanzar en paralelo

- Pieza 1: `fn doctor capabilities --emit-claude-md` (Go).
- Pieza 3: `fn_match` binario (Go).
- Pieza 5: `ids_naming` validator + endurecer (Go + rules).
- Pieza 7: clausula en `registry_calls.md` (rules, instant).

### Tanda B — depende de tanda A (consume binarios)

- Pieza 2: hook `UserPromptSubmit` consume `fn doctor capabilities` output.
- Pieza 4: hook `PreToolUse` consume `fn_match`.

### Tanda C — refuerzos

- Pieza 6: extension de `/fn_claude` skill.

## Acceptance criteria

- [ ] `fn doctor capabilities --emit-claude-md` imprime bloque markdown valido pegable en CLAUDE.md.
- [ ] Hook `UserPromptSubmit` añade linea `FRESH: <id1>, <id2>, ...` cada turno (max 5 funciones de los ultimos 7d).
- [ ] `fn_match "taskkill registry_dashboard.exe"` devuelve `deploy_cpp_exe_to_windows_bash_infra` con score > threshold en < 50ms.
- [ ] Hook `PreToolUse` con `fn_match` muestra hint `USE: ...` en al menos 3 patrones reproducibles (taskkill, cp Desktop, cmd.exe start).
- [ ] Validator de `fn_create_function` rechaza nombres no predictibles (sin verbo o sin dominio).
- [ ] `/fn_claude` tras crear N funciones, MEMORY.md tiene N nuevas lineas `[[id]] — purpose`.
- [ ] Reglas: `registry_calls.md` documenta la excepcion explicita para hooks.

## Metricas de exito

Antes / despues, ventana 7d:
- `Reg %` (% calls con function_id != '') — esperado +10pp.
- `violations` count — esperado -50%.
- Tiempo medio entre "patron inline" y "uso de funcion correspondiente" — esperado dia 1 → mismo turno.

Visibles en Monitor tab del `registry_dashboard`.

## Notas

- Capa 3 (fuzzy interceptor) es la mas potente pero requiere **benchmark** de latencia antes de habilitar en cada Bash. Si supera 100ms, degradar a "solo en comandos > N chars" o "solo al final del turno".
- No introducir mas reglas: las que hay (`registry_first.md`, `delegation.md`, `registry_calls.md`) son suficientes. Esto es **infraestructura para que se cumplan**.
