---
name: audit_copied_code
lang: go
domain: infra
version: 0.1.0
purity: impure
kind: function
description: "Audita apps en busca de cuerpos de funcion copiados del registry sin import. Calcula fingerprint normalizado (strip comments + whitespace) por funcion del registry y por funcion declarada en apps/, projects/*/apps/. Reporta matches exactos. MVP: exact_copy con sha256 truncado. Issue 0085k."
tags: [audit, drift, monitoring, registry, doctor, copied-code]
signature: "func AuditCopiedCode(registryRoot string) ([]CopiedCodeEntry, error)"
error_type: "error_go_core"
returns_optional: false
params:
  - name: registryRoot
    desc: "Path absoluto al directorio raiz del fn_registry (contiene registry.db). El audit busca apps/ y projects/*/apps/ dentro."
output: "Lista de CopiedCodeEntry: {app_file, app_function, registry_id, body_hash, similarity, kind}. similarity=1.0 y kind='exact_copy' en MVP."
uses_functions: []
uses_types: []
imports:
  - crypto/sha256
  - database/sql
  - io/fs
  - os
  - path/filepath
  - regexp
  - strings
  - github.com/mattn/go-sqlite3
example: |
  import "fn-registry/functions/infra"

  entries, err := infra.AuditCopiedCode("/home/lucas/fn_registry")
  if err != nil { ... }
  for _, e := range entries {
      fmt.Printf("%s:%s ~ %s (%s, %.2f)\n",
          e.AppFile, e.AppFunction, e.RegistryID, e.Kind, e.Similarity)
  }
file_path: "functions/infra/audit_copied_code.go"
tested: false
notes: |
  Pipeline interno:
  1. Lee `registry.db.functions(id, lang, code, file_path)` para construir
     fingerprint index `hash → [registry_id, ...]`. Cada `code` se parsea por
     `extractFunctions(code, lang)` para indexar cada funcion declarada
     dentro del archivo (importante para `.py` que contiene varias).
  2. Construye skip-set con los `file_path` del registry para no flagear la
     funcion como copia de si misma.
  3. Walk recursivo de `apps/` y `projects/*/apps/`. Skip de `.git`,
     `.venv`, `node_modules`, `__pycache__`, `build`, `dist`, `vendor`,
     `.pytest_cache`, `.cache`.
  4. Por cada archivo `.go/.py/.sh/.ts/.cpp`, extrae funciones y hash.
  5. Match en fpIndex → emite CopiedCodeEntry.

  Normalizacion:
  - Go/TS/C++: strip `//...` y `/* ... */`, collapse whitespace.
  - Python: strip docstrings (triple quotes), strip `#...` lines, collapse.
  - Bash: strip `#...` lines, collapse.

  Hash: sha256 hex truncado a 16 chars del cuerpo normalizado. Cuerpos
  con menos de 20 chars normalizados se descartan (trivialmente similares).

  Limitaciones MVP:
  - Solo exact_copy. near_copy/partial_match (fuzzy hash, AST SimHash,
    embeddings) en fase futura.
  - extractFunctions con regex naive. Falla con:
    - signatures multi-linea
    - lambdas y closures
    - metodos con receivers complejos
    - cadenas/comentarios con `{` dentro
  - C++ regex es la mas fragil (templates, namespaces, multiple inheritance).
  - No detecta copias con renames de variables. Para eso = fuzzy hash.

  Privacidad: solo se persisten paths, function names, y hashes. Nunca
  contenido del codigo. El cuerpo solo vive en memoria durante el audit.
---
