---
name: audit_app_location
kind: function
lang: go
domain: infra
version: "1.0.0"
purity: impure
signature: "func AuditAppLocation(repoRoot string) ([]AppLocationViolation, error)"
description: "Detecta artefactos (apps y analyses) ubicados en carpetas de lenguaje (cpp/apps/, python/apps/, bash/apps/, frontend/apps/, y sus equivalentes /analysis/). Estas ubicaciones violan la convencion del registry (issue 0096): los artefactos deben vivir en apps/ o analysis/ en la raiz, o en projects/*/apps/ y projects/*/analysis/. Retorna una lista de AppLocationViolation con la ruta relativa, kind (app|analysis) y lang (cpp|python|bash|frontend)."
tags: [doctor, audit, location, artefacts, registry]
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: "error_go_core"
imports: ["os", "path/filepath"]
params:
  - name: repoRoot
    desc: "Ruta absoluta a la raiz del repositorio fn_registry. Todas las rutas en las violaciones son relativas a este directorio."
output: "Lista de AppLocationViolation con (Path, Kind, Lang) por cada artefacto mal ubicado. Vacia si no hay violaciones. Error si un directorio prohibido existe pero no es legible."
tested: true
tests:
  - "detecta app.md en directorio prohibido cpp/apps"
  - "directorios prohibidos inexistentes no producen error"
  - "detecta analysis.md en directorio prohibido python/analysis"
test_file_path: "functions/infra/audit_app_location_test.go"
file_path: "functions/infra/audit_app_location.go"
---

## Ejemplo

```go
violations, err := AuditAppLocation("$HOME/fn_registry")
if err != nil {
    log.Fatal(err)
}
for _, v := range violations {
    fmt.Printf("[%s/%s] %s → mover a apps/%s o projects/.../apps/%s\n",
        v.Lang, v.Kind, v.Path,
        filepath.Base(v.Path), filepath.Base(v.Path))
}
// Ejemplo de salida:
// [cpp/app] cpp/apps/my_tool → mover a apps/my_tool o projects/.../apps/my_tool
```

## Cuando usarla

Usar como check de `fn doctor artefacts` o en pre-commit para detectar artefactos que se crearon en la carpeta del lenguaje equivocada. Invocar despues de `fn index` para validar el estado del repo.

## Gotchas

- Solo revisa subdirectorios de nivel 1 dentro de cada directorio prohibido. No escanea recursivamente.
- Un subdirectorio sin `app.md` ni `analysis.md` NO se reporta (ej. `cpp/apps/bar/` sin manifest = ignorado).
- Los artefactos en `apps/`, `analysis/`, `projects/*/apps/` y `projects/*/analysis/` son ubicaciones canonicas y NO se comprueban.
- `AppLocationViolation` esta definida en el mismo paquete (`infra`), no como tipo separado del registry.
