Commit Graph

2 Commits

Author SHA1 Message Date
Sergio 820a1a33bf feat(nouser): centroid_model — versionado de embeddings
Protege contra el bug silencioso de mezclar centroides de modelos
distintos (mock 32-d vs real 384-d), que daría scores sin sentido.

- MonadManifest.centroid_model: Option<String>. None = legacy.
- nouser_core::embed::MODEL_ID = "nouser-pseudo-32d". Cluster lo
  setea en cada Mónada que genera.
- nouser-nous-mock reusa la misma constante (use
  nouser_core::embed::MODEL_ID): produce vectores idénticos al
  cluster local, reportar el mismo ID es honesto.
- nouser-nous-real ya reportaba "real-fastembed-allMiniLML6V2-384d";
  el filter ahora lo descarta automáticamente cuando los centroides
  cacheados son del mock.
- cmd_attract:
  - Captura el model_id del embedding del target.
  - Filtra Mónadas cuyo centroid_model no matchee.
  - Reporta "embed: <source> (<model>)" y "skipped: N" cuando
    descarta.

Resultado: cambiar de mock a real vía BRAHMAN_BROKER_CONTEXT=prod
hace que attract filtre las Mónadas viejas con cero score en lugar
de fingir que las puede comparar.

Tests: 7 (card) + 24 (core) verdes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 00:24:38 +00:00
Sergio 77faf12e82 feat(nouser): Phase C — pseudo-embeddings + atracción por centroide
El "imán semántico" matemático del diseño Kairos, sin LLM. Cada
archivo se proyecta a un vector 32-d determinista derivado de sus
metadatos; cada Mónada calcula su centroide; archivos nuevos se
asignan por cosine similarity contra los centroides existentes.

Cambios:

- nouser-core dep nueva: blake3 (hash determinista de strings).
- crates/modules/nouser/core/src/embed.rs nuevo:
  - EMBED_DIM = 32. Vector:
    * dims 0..8:  blake3(extension)
    * dims 8..16: blake3(parent_dir)
    * dims 16..24: blake3(file_stem)
    * dims 24..28: tamaño (log + flags)
    * dims 28..32: mtime (escala día + features cíclicas)
  - Tip clave: hash bytes se centran a [-1, 1] (no [0, 1]). Sin
    centrar, dos hashes random tendrían cosine ~0.75 espurio.
    Centrados, expectativa ≈ 0 entre no-relacionados.
  - APIs: embed, cosine_similarity, centroid, cohesion,
    attraction_score, best_attraction. DEFAULT_ATTRACTION_THRESHOLD = 0.7.
- cluster::by_directory ahora computa el centroide de cada Mónada
  y lo guarda en MonadManifest.centroid. El centroide viaja al
  brahman-status vía DataFacet.centroid.
- bin nouser nuevo subcomando: attract <dir> <file>.
  - Scan del dir, embedding del archivo objetivo, ranking de afinidad
    contra Mónadas con centroide.
  - 🧲 si la mejor supera umbral, · si es mejor pero debajo.

Validación end-to-end:

  $ nouser attract crates/core crates/modules/nouser/core/src/embed.rs
    🧲  0.9058  [01K..] src  (ente-brain/src)
        0.8984  [01K..] src  (brahman-handshake/src)
        ...

  $ nouser attract crates/core crates/modules/nouser/core/Cargo.toml
        0.3427  [01K..] graph  (ente-zero/src/graph)
    (mejor score 0.3427 < umbral 0.7000 — no se 'pega')

7 tests nuevos en embed (determinismo, normalización, similitud
mismo-dir/mismo-ext, baja entre no-relacionados, centroide
unidad+coherente, attraction picks correctly, vacío skipeado).

Tests acumulados: 73. cargo check --workspace: 0 errores, 0 warnings.

Próximo: Phase D — nouser-nous, módulo aparte para LLM real.
Mock-nous determinista (basado en estos pseudo-embeddings) en
BRAHMAN_BROKER_CONTEXT=test; real-nous en prod. El switch lo hace
el broker via priority_contexts.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 18:31:04 +00:00