refactor(monorepo): reorganización lógica + renames + SDDs + split CHANGELOG
Reorganización física de crates/: - core/ (mezclaba 6 propósitos) se divide en protocol/, init/, runtime/, compat/ - shared/ (3 crates) se redistribuye en protocol/ e init/ - lapaloma (sub-módulo de ui_engine) se promueve a modules/pineal/ Renames de proyectos: - shipote → shuma (runtime de sandboxes) - nouser → akasha (explorador de Mónadas) - yahweh → nahual (motor GPUI, antes ui_engine/) - lapaloma → pineal (data-viz agnóstica) Fraccionamiento UI → core agnóstico: - vista-core (DeckState + snap, 175 LOC, 5 tests verdes) - barra-core (Task + render_html + sanitize, 90 LOC, 5 tests verdes) - vista-web y barra-web ahora son thin DOM bindings Documentación nueva: - 16 SDDs por subdirectorio (≤80 LOC c/u): protocol/init/runtime/compat + 10 módulos + apps/ - docs/STATUS.md con cifras reales por proyecto - docs/ROADMAP.md con plan a finalización (6 hitos, ~6-8 semanas) - CHANGELOG.md particionado en docs/changelog/<proyecto>.md (7 buckets) Automatización: - scripts/reorg.py — script idempotente que: git mv directorios, renombra package names, recomputa path = refs, reescribe imports rust, actualiza workspace Cargo.toml. Soporta --dry-run. - scripts/split-changelog.py — particiona CHANGELOG por componente. Validación: - cargo check --workspace pasa (124 crates + 2 nuevos cores). - 10 tests adicionales (5 en vista-core + 5 en barra-core) verdes. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,316 @@
|
||||
# Changelog — minga (semantic_dht)
|
||||
|
||||
### feat(minga-explorer): listings de items recientes en cada stat card
|
||||
Iter 12. Hasta ahora minga-explorer mostraba sólo counts (3
|
||||
números). Ahora cada stat card muestra también un sample de los
|
||||
items dentro: hashes truncados de los 5 primeros nodos AST
|
||||
(con su `kind`), atestaciones (`content_hash ← did_short`) y
|
||||
claves MST. Mucho más útil para debugging que el "tengo N items".
|
||||
|
||||
Cambios en `minga-explorer`:
|
||||
- **`RepoSnapshot` extendido** con 3 nuevos `Vec<...>`:
|
||||
- `recent_nodes: Vec<(String, String)>` — `(hash_short, kind)`.
|
||||
- `recent_attestations: Vec<(String, String)>` —
|
||||
`(content_hash_short, did_short)`.
|
||||
- `recent_mst_keys: Vec<String>` — `hash_short`.
|
||||
- Cap de 5 items por sección via `RECENT_LIMIT` const.
|
||||
- **`load_snapshot` itera los stores** y toma los primeros 5
|
||||
items via `iter().filter_map(Result::ok).take(RECENT_LIMIT)`.
|
||||
Errores per-item se silencian (`filter_map`) — el dashboard
|
||||
muestra lo que pueda; un par de items corruptos no debería
|
||||
tirar el panel.
|
||||
- **`short_hash(&str)` helper local**: trunca un hex a sus
|
||||
primeros 12 chars (48 bits, distintivo dentro de un repo
|
||||
single-machine).
|
||||
- **`stat_card` extendido**: nuevo arg `recent_items: &[String]`.
|
||||
Si no está vacío, agrega un sub-header `"recent (N de TOTAL):"`
|
||||
+ una linea por item. Cada line es texto pequeño (`px(11)`)
|
||||
con el color principal del theme — visualmente queda como
|
||||
monospace listing aunque no use mono font (no hay todavía
|
||||
en el theme).
|
||||
|
||||
Tests: 2 → **4** (+2 sanity de los nuevos defaults + del
|
||||
`short_hash`).
|
||||
|
||||
Beneficio operativo:
|
||||
- Después de `minga ingest archivo.rs`, el explorer muestra
|
||||
inmediatamente los hashes de los nodos AST creados, qué `kind`
|
||||
tienen, y las atestaciones firmadas — sin necesitar `minga
|
||||
status` o queries SQL.
|
||||
- "5 de 247" da contexto del crecimiento sin overwhelm de
|
||||
listing completo.
|
||||
|
||||
Limitación documentada: los "recent" no son cronológicos — sled
|
||||
ordena lexicográfico por hash. Para timeline real, agregar
|
||||
timestamp al schema (cambio breaking del store, scope futuro).
|
||||
|
||||
### feat(minga-explorer): nueva app dashboard del repo Minga sobre stack yahweh
|
||||
Iter 11. Cierra el último frente identificado: integración del
|
||||
módulo Minga (VCS semántico P2P) al ecosistema GUI. Antes Minga
|
||||
sólo tenía CLI (`minga init/status/ingest/listen/sync/watch`).
|
||||
Ahora hay un **dashboard GPUI** que muestra los counts del repo
|
||||
en vivo, sobre el mismo stack themed que las otras dos apps
|
||||
explorer.
|
||||
|
||||
Crate nuevo `crates/apps/minga-explorer/`:
|
||||
- **Deps**: `minga-store` (para `PersistentRepo::open`) +
|
||||
`yahweh-theme` + `yahweh-widget-{banner,card,theme-switcher}`.
|
||||
Sin `minga-cli` (no necesita prompts de passphrase) ni
|
||||
`minga-core` (counts no requieren parsear AST).
|
||||
- **Lectura sin passphrase**: el `PersistentRepo` se abre directo
|
||||
desde `<repo>/repo` sled. Los counts (`nodes.len()`,
|
||||
`attestations.len()`, `mst.len()`) son lectura pública. Para el
|
||||
DID se sigue necesitando `minga status` (CLI con passphrase).
|
||||
- **Refresh por polling cada 2s**: mismo pattern que
|
||||
`nakui-explorer`/`nouser-explorer`.
|
||||
- **3 stat cards** una por dimensión:
|
||||
- Nodos AST (cyan) — fragments parseados del código.
|
||||
- Atestaciones (verde) — firmas Ed25519 sobre los nodos.
|
||||
- Claves MST (purple) — entradas del Merkle Search Tree.
|
||||
- **Helper `stat_card(cx, label, value, description, accent, ...)`**:
|
||||
fabrica una card con border-l colored + label tenue + número
|
||||
grande (`px(28)`) + descripción. Reutilizable.
|
||||
- **Header**: título dinámico (`Repo: <path> · reload <ms> ms`)
|
||||
+ theme switcher derecha.
|
||||
- **Error banner**: themed Banner::Error si el repo no abre.
|
||||
- 2 tests: `load_snapshot_errors_on_missing_dir` (msg claro
|
||||
cuando el dir no existe) + sanity del `RepoSnapshot::default`.
|
||||
|
||||
Workspace: nueva entry en `members[]`.
|
||||
|
||||
Smoke run del binario verificado: bootstrap completo OK, panic
|
||||
esperado en open_window por falta de display.
|
||||
|
||||
Beneficio operativo:
|
||||
- Un usuario corre `minga init` + `minga ingest archivo.rs` desde
|
||||
CLI, después abre `minga-explorer` y ve los counts crecer en
|
||||
vivo cuando ingiere más archivos.
|
||||
- Comparte theme switcher con `nakui-explorer` y
|
||||
`nouser-explorer` — cualquier preset elegido se aplica
|
||||
visualmente igual cross-app.
|
||||
- `minga` deja de ser sólo CLI; gana presencia GUI sin tocar
|
||||
el resto del módulo.
|
||||
|
||||
Apps GUI integradas al stack themed: **4** (nakui-ui, nakui-explorer,
|
||||
nouser-explorer, minga-explorer).
|
||||
|
||||
### feat(minga-core): α-hashing per-language para Python, TypeScript, JavaScript, Go
|
||||
Cierra el último pendiente fundamentado del CHANGELOG. Cada lenguaje
|
||||
soportado por `minga` tiene ahora su propio profile α-equivalente —
|
||||
dos versiones del mismo programa que difieren sólo en nombres de
|
||||
variables ligadas producen el mismo hash, no importa el lenguaje.
|
||||
Refactorings tipo "rename variable" no inflan el storage del repo
|
||||
en ningún dialecto.
|
||||
|
||||
Refactor de `alpha.rs` (639 LOC) a módulo `alpha/`:
|
||||
- **`alpha/common.rs`**: primitives compartidos (TAG_*, write_kind_and_field,
|
||||
emit_leaf_marker, emit_binder_body, emit_identifier_ref, push_identifier_name).
|
||||
Garantiza que el formato wire del hash sea bit-equivalente entre
|
||||
todos los profiles.
|
||||
- **`alpha/rust.rs`**: la lógica de Rust (movida desde alpha.rs sin
|
||||
cambios funcionales).
|
||||
- **`alpha/python.rs`**: nuevo.
|
||||
- **`alpha/ecmascript.rs`**: nuevo (cubre TypeScript + JavaScript;
|
||||
comparten la mayoría de los kinds).
|
||||
- **`alpha/go.rs`**: nuevo.
|
||||
- **`alpha/mod.rs`**: re-exporta `hash_node_alpha` (Rust legacy) +
|
||||
expone `hash_alpha_with(dialect, node)` que despacha al profile
|
||||
correspondiente.
|
||||
|
||||
Cobertura per-language:
|
||||
|
||||
**Python** (`def`, `lambda`, `for`, comprehensions, `with`):
|
||||
- `function_definition` y `lambda`: parámetros (incluyendo
|
||||
typed_parameter, default_parameter, *args, **kwargs) introducen
|
||||
binders al body. El nombre de la función NO es α-anónimo.
|
||||
- `for_statement`: el `left` (identifier o tuple) introduce
|
||||
binder(es) al body.
|
||||
- `list_comprehension`, `set_comprehension`, `dictionary_comprehension`,
|
||||
`generator_expression`: cada `for_in_clause` añade binders que
|
||||
viven en el body + clauses siguientes (semántica de scope
|
||||
incremental de Python).
|
||||
- `with_statement`: `as` introduce binder al body (recursando en
|
||||
`as_pattern_target` para llegar al identifier).
|
||||
|
||||
**ECMAScript** (TS + JS):
|
||||
- `function_declaration`, `function_expression`, `method_definition`,
|
||||
`generator_function_*`: parameters → body. Soporta TS
|
||||
`required_parameter` y `optional_parameter` (`x: number`,
|
||||
`x?: number`).
|
||||
- `arrow_function`: tanto `(x, y) => body` como shorthand `x => body`.
|
||||
- `statement_block`: `lexical_declaration` (let/const) y
|
||||
`variable_declaration` (var) introducen binders al resto del block.
|
||||
- `for_in_statement` (cubre `for-of` y `for-in`): `left` → body.
|
||||
- `for_statement` (C-style): initializer (lexical decl) introduce
|
||||
binders al condition + increment + body.
|
||||
- `catch_clause`: parameter → body.
|
||||
|
||||
**Go**:
|
||||
- `function_declaration`, `method_declaration`, `func_literal` (closure):
|
||||
`parameter_list` → body. `parameter_declaration` con varios names
|
||||
agrupa varios binders bajo un mismo tipo (`a, b int`).
|
||||
- `block`: `short_var_declaration` (`x := ...`) introduce binders
|
||||
al resto.
|
||||
- `for_statement` con `range_clause` (`for k, v := range m`): los
|
||||
identifiers del `left` son binders al body.
|
||||
- `for_statement` con `for_clause` (C-style): initializer → body.
|
||||
- `if_statement` con `initializer` (`if x := init(); x > 0`):
|
||||
binders viven en condition + consequence + alternative.
|
||||
|
||||
API:
|
||||
- `hash_alpha_with(Dialect, &SemanticNode) -> ContentHash` —
|
||||
despacho per-dialect.
|
||||
- `hash_node_alpha(&SemanticNode) -> ContentHash` — alias histórico
|
||||
asume Rust (back-compat).
|
||||
|
||||
Tests: 26 nuevos en `tests/alpha_polyglot.rs`:
|
||||
- Python (9): def rename, lambda rename, for-loop rename, list comp,
|
||||
nested comp, with rename, function name matters, iterable name
|
||||
matters, sanity negativo (operación distinta → hash distinto).
|
||||
- JS/TS (9): function rename, function name matters, arrow rename,
|
||||
arrow shorthand rename, let/const rename, for-of rename, classic
|
||||
for rename, catch rename, TS typed param rename, TS type matters.
|
||||
- Go (6): function rename, function name matters, short var decl
|
||||
rename, range_clause rename, if-init rename, func_literal closure
|
||||
rename.
|
||||
- Cross-language (1): mismos shapes en lenguajes distintos
|
||||
producen hashes distintos (sanity para evitar colisiones).
|
||||
|
||||
141 tests verdes en minga-core (115 antes; +26 polyglot). Refactor
|
||||
sin regresión: 36 α-Rust tests siguen pasando.
|
||||
|
||||
Pendientes que quedan en Minga (orden de prioridad):
|
||||
- `minga-vfs` FUSE (proyecto independiente, scope grande).
|
||||
- Cobertura adicional por-lenguaje: Python class, JS destructuring,
|
||||
Go type_switch, etc. — cada uno pequeño, no urgente.
|
||||
|
||||
### feat(minga-core): cierre del α-hashing de Rust — if let, while let, let-else, or-pattern, let-chains
|
||||
Cierra los 5 pendientes documentados en `alpha.rs`. El hash
|
||||
α-equivalente ahora es estable bajo renombre de TODOS los binders
|
||||
de Rust, no sólo los del MVP (parámetros, let, for, match arms).
|
||||
|
||||
Pendientes cerrados:
|
||||
- **`if let X = expr { ... }`**: `if_expression` detecta
|
||||
`let_condition` en su `condition`, recolecta los binders del
|
||||
pattern, los propaga al `consequence`. El `alternative` (else)
|
||||
NO los ve.
|
||||
- **`while let X = expr { ... }`**: simétrico al if-let, propaga al
|
||||
`body`. El `condition` mismo se evalúa con scope previo (los
|
||||
binders todavía no existen).
|
||||
- **`let-else`**: `let_declaration` con campo `alternative`. El
|
||||
alternative se procesa con el scope ANTES de los binders (ya
|
||||
funcionaba: `feed_let` llama `feed` para no-pattern children con
|
||||
el scope actual; `feed_block` extiende el scope DESPUÉS de
|
||||
`feed_let`).
|
||||
- **`or_pattern`**: en `pat1 | pat2` (Rust enforcement: ambos lados
|
||||
introducen los mismos binders). Para emit, recorremos cada lado
|
||||
con `feed_pattern`. Para collect, sólo el primer lado — iterar
|
||||
todos duplicaría binders y rompería los índices de Bruijn.
|
||||
- **let-chains** (`if let X = a && let Y = b { ... }`): el
|
||||
`collect_let_condition_binders` recursa en el árbol del condition,
|
||||
capturando todos los `let_condition` (vivan dentro de
|
||||
`binary_expression` u otros nodos). Ambos binders quedan en scope
|
||||
del consequence.
|
||||
|
||||
Helper nuevo: `feed_let_condition` para que el `pattern` del
|
||||
let_condition pase por `feed_pattern` (que distingue binders vs
|
||||
constructors). Sin esto, los identifiers del pattern se hasheaban
|
||||
como variables libres y `Some(x)` ≠ `Some(y)` aún teniendo el
|
||||
mismo significado.
|
||||
|
||||
Tests: 6 nuevos en `tests/alpha_invariants.rs`:
|
||||
- `alpha_if_let_binder_rename_invariant`
|
||||
- `alpha_if_let_else_does_not_see_binder` (sanity)
|
||||
- `alpha_while_let_binder_rename_invariant`
|
||||
- `alpha_let_else_binder_rename_invariant`
|
||||
- `alpha_or_pattern_binder_rename_invariant`
|
||||
- `alpha_let_chain_binders_propagate_to_consequence`
|
||||
- `alpha_if_let_does_not_collide_with_unrelated_program` (negativo:
|
||||
programas distintos NO deben dar el mismo hash)
|
||||
|
||||
36 tests α verdes (eran 30). 115 tests totales en minga-core.
|
||||
|
||||
Lo que esto significa: el hash α-equivalente de Rust en minga es
|
||||
**completo** — cubre todos los constructos del lenguaje que
|
||||
introducen bindings. Dos versiones del mismo programa que difieren
|
||||
sólo en nombres de variables (incluyendo en `if let`, `while let`,
|
||||
`or-pattern`, etc.) producen el mismo hash y por tanto la misma
|
||||
identidad CAS. Refactorings del tipo "rename variable" no inflan
|
||||
el storage del repo.
|
||||
|
||||
Pendientes futuros:
|
||||
- α-hashing per-language (Python: def/lambda/comprehensions; TS/JS:
|
||||
function/arrow/destructuring; Go: func/closure). Cada uno
|
||||
requiere conocimiento profundo de la gramática y tests
|
||||
exhaustivos. Plantilla genérica no aplica.
|
||||
|
||||
### feat(minga): multi-lenguaje en parser — Python, TypeScript, JavaScript, Go
|
||||
Minga deja de ser Rust-only. Cualquiera de los cinco dialectos
|
||||
(Rust + 4 nuevos) se ingresa al CAS por su AST normalizado, hashea
|
||||
estructuralmente, sincroniza por DHT como cualquier nodo. La
|
||||
auto-detección por extensión hace que `minga ingest archivo.py` o
|
||||
`.ts` o `.go` "simplemente funcione".
|
||||
|
||||
API nueva en `minga_core::parse`:
|
||||
- Funciones por dialecto (~6 LOC c/u sobre el `parse_with` común):
|
||||
`python`, `typescript`, `javascript`, `go`. Más la `rust` existente.
|
||||
- Enum `Dialect` con `parse(source) -> Result<SemanticNode>` y
|
||||
`name() -> &'static str` para logging.
|
||||
- `detect_by_extension(ext) -> Option<Dialect>`: mapea `rs`/`py`/
|
||||
`pyi`/`ts`/`js`/`mjs`/`cjs`/`go` (case-insensitive). `None` para
|
||||
extensiones desconocidas — el caller decide si es error o se
|
||||
ignora silente.
|
||||
|
||||
Wire en `minga-cli`:
|
||||
- `cmd_ingest` deja de hardcodear `parse::rust` — usa
|
||||
`detect_dialect(file)?.parse(...)`. Acepta `.py`, `.ts`, `.js`,
|
||||
`.go` además de `.rs`.
|
||||
- `initial_scan` y `cmd_watch` cambian `is_rs_file` → `is_supported_source`
|
||||
para incluir todas las extensiones soportadas en el filtro.
|
||||
- `CliError::UnsupportedLanguage { path, extension }` nuevo, con
|
||||
mensaje que lista las extensiones reconocidas.
|
||||
|
||||
Notas sobre hashing:
|
||||
- El AST normalizado (`SemanticNode`) descarta whitespace y
|
||||
comentarios — propiedad universal de tree-sitter (extras). Misma
|
||||
lógica para los 5 dialectos.
|
||||
- Hashing **estructural** (`cas::hash_node`) funciona para todos:
|
||||
dos textos semánticamente equivalentes-por-estructura producen el
|
||||
mismo hash. NO α-equivalente (las variables ligadas distinguen).
|
||||
- Hashing **α-equivalente** (`alpha::hash_node_alpha`) sigue siendo
|
||||
Rust-only: cada lenguaje tiene reglas distintas para qué es
|
||||
binder vs. constructor (def/lambda en Python, arrow functions en
|
||||
TS/JS, func + closures en Go). Implementación per-language queda
|
||||
como work futuro — requiere conocimiento profundo de cada
|
||||
gramática y no se plantilla genéricamente.
|
||||
- Sanity test `structural_hash_distinguishes_languages` verifica
|
||||
que `x = 1` parseado como Python ≠ parseado como JavaScript: las
|
||||
gramáticas no comparten kinds y los hashes salen distintos.
|
||||
Importante para evitar colisiones cuando el mismo source se
|
||||
ingresa bajo dialectos distintos.
|
||||
|
||||
Deps nuevas (workspace + minga-core):
|
||||
- `tree-sitter-python = "0.23"`
|
||||
- `tree-sitter-typescript = "0.23"` (sólo el modo `LANGUAGE_TYPESCRIPT`,
|
||||
no TSX — bumpear a TSX es agregar otro dialecto cuando se necesite).
|
||||
- `tree-sitter-javascript = "0.23"`
|
||||
- `tree-sitter-go = "0.23"`
|
||||
|
||||
Tests:
|
||||
- 9 nuevos en `parse::tests`: parse básico para los 5 dialectos
|
||||
(Python con type hints, TS con tipos, JS sin tipos, Go con
|
||||
package declaration), `detect_by_extension` canonical +
|
||||
case-insensitive, `dialect_name`, `structural_hash_distinguishes_languages`.
|
||||
- 108 tests verdes en minga-core (39 → 48 unit + integration tests
|
||||
pre-existentes intactos).
|
||||
- 10 tests verdes en minga-cli (sin regresión en el path Rust;
|
||||
el refactor a `detect_dialect`/`is_supported_source` no rompe
|
||||
nada).
|
||||
|
||||
Pendientes futuros del changelog:
|
||||
- α-hashing per-language (Python: def/lambda/comprehensions;
|
||||
TS/JS: function/arrow/destructuring; Go: func/closure). Trabajo
|
||||
profundo, scope independiente.
|
||||
- α-Rust pendientes documentados en `alpha.rs`: `if let`,
|
||||
`while let`, `let-else`, let-chains, `or_pattern` con bindings.
|
||||
|
||||
Reference in New Issue
Block a user