Files
fn_match/app.md
T
2026-05-14 02:06:41 +02:00

5.3 KiB

name, lang, domain, description, tags, uses_functions, uses_types, framework, entry_point, dir_path, repo_url, params, output
name lang domain description tags uses_functions uses_types framework entry_point dir_path repo_url params output
fn_match go infra Fuzzy matcher entre un comando shell o snippet heredoc y funciones del registry. Devuelve las top-N funciones mas probables que cubren ese patron, con score normalizado. Consumido por el hook PreToolUse para sugerir funciones del registry en vez de codigo inline.
discovery
hooks
match
fuzzy
registry
cmd/fn/match.go apps/fn_match
name desc
command Comando shell o snippet heredoc a analizar. Puede pasarse como argumento posicional o por stdin.
name desc
top Numero maximo de resultados a devolver (default 3).
name desc
format Formato de salida: json (default) o text.
name desc
min-score Umbral minimo de score normalizado 0..1 (default 0.3). Resultados por debajo se descartan.
JSON o texto con las top-N funciones del registry ordenadas por score descendente. Score 1.0 = mejor match; resto son relativos al top.

Ejemplo

# Arg posicional — JSON por defecto
./fn match "taskkill.exe /IM registry_dashboard.exe /F"

# Texto legible
./fn match --format text --top 5 "rsync -avz src/ user@host:/opt/app"

# Stdin pipe (util en hooks)
echo "curl -sf https://api.example.com/health | jq .status" | ./fn match

# Subir umbral para matches muy seguros solamente
./fn match --min-score 0.7 "encrypt file sha256"

Salida JSON:

{
  "query": "taskkill.exe /IM registry_dashboard.exe /F",
  "top": [
    {
      "id": "deploy_cpp_exe_to_windows_bash_infra",
      "score": 1,
      "signature": "deploy_cpp_exe_to_windows(app_name: string, app_dir: string) -> void",
      "snippet": "Copia el .exe de Windows... Mata el proceso si esta corriendo (taskkill.exe pre-autorizado)..."
    }
  ],
  "high_confidence": false
}

Cuando usarla

Hook PreToolUse (uso principal): El hook intercepta comandos Bash antes de ejecutarse. Si el comando supera el umbral de score, el hook inyecta en el contexto:

USE: deploy_cpp_exe_to_windows_bash_infra [score=1.000] instead of inline

Debug manual: Para entender por que Claude escribe cierto patron inline repetidamente, correr fn match con ese patron y ver si el registry ya cubre el caso.

Auditoria de gaps: Si fn match devuelve top: [] para un patron que aparece >3 veces en sesiones, ese patron es candidato a nueva funcion del registry.

Pipeline interno

  1. Tokenize: split por no-alfanumericos + eliminacion de flags (-v, /F), paths absolutos (conserva basename sin extension), numeros puros, tokens < 3 chars, y stopwords del dominio (registry, function, app, file, get, set, ...).
  2. FTS5 query: tok1 OR tok2 OR ... sobre functions_fts con bm25(). Resultado: hasta 50 candidatos con rank BM25.
  3. Fetch metadata: segundo query SELECT ... FROM functions WHERE id IN (...) para obtener name, signature, description, tags.
  4. Re-score aditivo: cada token suma su mejor boost de campo (name=+3.0, tags=+2.0, signature=+1.5, description=+1.0). No multiplicativo — evita que tokens genericos saturen todos los resultados a 1.0.
  5. Language penalty: si query tiene markers Python (def, import, class) y el hit es bash → x0.5. Si tiene markers bash (curl, rsync, taskkill, exe) y hit es py → x0.5.
  6. Normalizar: el top score raw se convierte en 1.0; el resto es relativo.
  7. Filtrar y limitar: --min-score descarta ruido; --top N limita salida.
  8. High confidence flag: top[0].score / top[1].score > 1.5"high_confidence": true.

Gotchas

Latencia: 6-7ms en WSL2 con 1255 funciones indexadas. Sin daemon — proceso fresh por invocacion. Bien por debajo del objetivo de 50ms.

FTS5 WAL: La conexion se abre en modo lectura normal (no mode=ro) porque bm25() con WAL no checkpointed falla con "missing row from content table". El binario nunca escribe.

FTS5 rebuild: Si fn match devuelve top: [] para queries que deberias matchear, el indice FTS5 puede estar desincronizado. Solucion:

// Rebuild manual del indice:
INSERT INTO functions_fts(functions_fts, rank) VALUES('rebuild', NULL);
INSERT INTO types_fts(types_fts, rank) VALUES('rebuild', NULL);
INSERT INTO unit_tests_fts(unit_tests_fts, rank) VALUES('rebuild', NULL);

O simplemente ./fn index — reindexar regenera el FTS5.

Stopwords del dominio: Tokens como registry, function, app, file, get, set se descartan del tokenizer porque matchean cientos de funciones igualmente y no aportan señal. Si un query solo tiene stopwords, fn match retorna error "no significant tokens".

Scores normalizados: El score 1.0 no significa "match perfecto" — es el mejor candidato relativo al batch. Un high_confidence: false con score 1.0 significa que el segundo candidato es similar. Para gates en hooks usar high_confidence: true como criterio.

Implementacion: cmd/fn/match.go en el modulo raiz fn-registry. Se compila junto al binario fn principal — no es un binario separado. Invocar como ./fn match ....

Capability growth log

  • v1.0.0 (2026-05-14): scoring multiplicativo inicial — todos los hits clampean a 1.0 cuando varios tokens matchean
  • v1.1.0 (2026-05-14): scoring aditivo por token con normalizacion relativa + stopwords del dominio. FTS5 rebuild fix. Latencia: 6-7ms