---
name: vault_inventory_scan
kind: function
lang: go
domain: infra
version: "1.0.0"
purity: impure
signature: "func VaultInventoryScan(vaultPath, vaultID, vaultName string) ([]VaultFile, error)"
description: "Recorre vaultPath con filepath.WalkDir y retorna un slice de VaultFile ordenado por RelPath para cada archivo regular, computando sha256 por streaming, MIME por extension/magic y bucket/sub-bucket por posicion en el arbol."
tags: [vault, inventory, scan, filesystem, sha256, mime, infra]
uses_functions: []
uses_types: ["vault_file_go_infra"]
returns: []
returns_optional: false
error_type: "error_go_core"
imports: [crypto/sha256, encoding/hex, fmt, io, net/http, os, path/filepath, sort, strings]
params:
  - name: vaultPath
    desc: "ruta absoluta o relativa al directorio raiz del vault"
  - name: vaultID
    desc: "identificador del vault (ej: turismo_spain_app_turismo) — se copia a cada VaultFile"
  - name: vaultName
    desc: "nombre legible del vault (ej: turismo_spain) — se copia a cada VaultFile"
output: "slice de VaultFile ordenado lexicograficamente por RelPath; slice vacio (no nil) si el vault esta vacio"
tested: true
tests:
  - "tmpdir vacio retorna slice vacio"
  - "data layout — bucket y sub_bucket correctos"
  - "knowledge layout — bucket y sub_bucket correctos"
  - "omite vault_index.db y .git"
  - "sha256 determinista para mismo contenido"
  - "orden lexicografico del resultado"
test_file_path: "functions/infra/vault_inventory_scan_test.go"
file_path: "functions/infra/vault_inventory_scan.go"
---

## Ejemplo

```go
files, err := VaultInventoryScan("/data/vaults/turismo_spain", "turismo_spain_v1", "turismo_spain")
if err != nil {
    log.Fatal(err)
}
for _, f := range files {
    fmt.Printf("%s  %s  %s/%s\n", f.RelPath, f.Mime, f.Bucket, f.SubBucket)
}
```

## Notas

### Archivos omitidos
- `vault_index.db`, `vault_index.db-shm`, `vault_index.db-wal` (siempre)
- `.git/` en cualquier profundidad (SkipDir)
- Entradas cuyo nombre empieza por `.` solo en la raiz del vault (nivel 0)

### Deteccion de MIME
`file_validate_type_go_infra` (FileValidateType) no se usa porque su firma
requiere una lista blanca de tipos permitidos y retorna (mime, bool) — esta
disenada para validacion de uploads, no para escaneo inventarial donde
cualquier MIME es valido. Se usan en su lugar:

1. Override por extension (prioridad alta): `.csv` → `text/csv`, `.md` → `text/markdown`,
   `.parquet` → `application/parquet`. Necesario porque `http.DetectContentType`
   clasifica CSV como `text/plain` y no conoce Parquet.
2. `http.DetectContentType` sobre primeros 512 bytes (magic bytes, stdlib) para el resto.

### SHA-256
Calculado por streaming con `io.Copy` a `sha256.New()` — no carga el archivo completo
a memoria. Valido para archivos de cualquier tamano.

### Bucket / SubBucket
Derivados de la posicion en el arbol:
- `bucket` = primer segmento del RelPath (tipicamente "data" o "knowledge")
- `subBucket` = segundo segmento si existe; vacio si el archivo esta en la raiz del bucket
