feat(minga): minga-vfs — proyecta el repo como filesystem FUSE
minga-vfs deja de ser un stub: monta el repositorio direccionado por contenido como un filesystem FUSE de sólo lectura. roots/<hash> da el código fuente reconstruido (formato normalizado) de cada raíz del MST; cas/<hash> resuelve cualquier hash bajo demanda como S-expression. Capas separadas: render (SemanticNode→texto, puro) + source (contrato NodeSource, backends sled/memoria) + fs (único módulo con fuser). Nuevo subcomando `minga mount <punto>`. Dep fuser 0.15 sin libfuse-dev (default-features = false). 14 tests nuevos, sin regresión en minga-cli. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,57 @@
|
||||
# Changelog — minga (semantic_dht)
|
||||
|
||||
### feat(minga-vfs): VFS FUSE — el repo como filesystem de sólo lectura
|
||||
`minga-vfs` deja de ser un stub de 2 LOC: ahora monta el repositorio
|
||||
direccionado por contenido como un filesystem FUSE navegable con
|
||||
`ls`/`cat`/`grep`/un editor, sin exponer `sled`.
|
||||
|
||||
Layout del montaje:
|
||||
- `README` — explicación del propio VFS.
|
||||
- `roots/<hash>` — un archivo por raíz del MST (cada archivo
|
||||
ingerido), con el código fuente **reconstruido** en formato
|
||||
normalizado. `ls roots/` las enumera todas.
|
||||
- `cas/<hash>` — la S-expression del subárbol de cualquier hash.
|
||||
Este directorio NO se enumera (decenas de miles de nodos) pero
|
||||
`cat cas/<hash>` resuelve cualquier hash conocido: es el "blob
|
||||
por hash bajo demanda" que la SDD pedía.
|
||||
|
||||
Arquitectura, separando por capas (ver feedback de separabilidad):
|
||||
- **`render`** — `SemanticNode` → texto. Lógica pura, sin IO ni
|
||||
FUSE. `render_source` re-imprime los tokens hoja con un
|
||||
pretty-printer mínimo consciente de llaves (indenta tras `{`,
|
||||
corta tras `;`); `render_sexp` vuelca el árbol literal. El render
|
||||
de fuente es normalizado, no byte-exacto: el AST descartó
|
||||
whitespace y comentarios al ingerir. Python, cuya estructura vive
|
||||
en la indentación, sale como secuencia de tokens — esperado.
|
||||
- **`source`** — el contrato `NodeSource` (`roots()` + `get()`) y
|
||||
`reconstruct()`. Backends: `RepoSource` sobre el `PersistentRepo`
|
||||
de `sled`, `MemSource` en RAM (tests / índices efímeros).
|
||||
- **`fs`** — único módulo acoplado a `fuser`: implementa la
|
||||
`Filesystem` trait. Inodos estáticos reservados (1-4), dinámicos
|
||||
desde 16 con tabla `(padre, nombre) → inodo` estable. Cada
|
||||
archivo se renderiza y cachea en el primer `lookup`.
|
||||
|
||||
Dep nueva (workspace + minga-vfs):
|
||||
- `fuser = "0.15"` con `default-features = false`: prescinde de
|
||||
`pkg-config`/`libfuse-dev` en build; el montaje pasa a Rust puro
|
||||
(helper `fusermount3` en runtime).
|
||||
|
||||
CLI: nuevo subcomando `minga mount <punto>` (`cmd_mount`), que abre
|
||||
el repo, lo envuelve en `RepoSource` y bloquea hasta
|
||||
`fusermount -u <punto>`. Pide la passphrase igual que `status`.
|
||||
|
||||
Tests: **14** nuevos en minga-vfs (9 unit: render con llaves,
|
||||
S-expression con campos/escape, parseo de hash de 64 hex, roundtrip
|
||||
de `MemSource`; 5 integration: ingest→reconstruct lossless a nivel
|
||||
AST, `roots/` lista todo, vistas source/sexp, deduplicación de
|
||||
subárboles). Los 10 tests de minga-cli intactos (sin regresión).
|
||||
|
||||
Pendientes:
|
||||
- `cas/` cachea contenido sin tope: navegar un repo gigante crece
|
||||
en RAM. Un LRU sería el siguiente paso si molesta.
|
||||
- Sin extensión en los nombres (`roots/<hash>`): no guardamos el
|
||||
lenguaje original, así que el editor no autodetecta sintaxis.
|
||||
|
||||
### 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
|
||||
|
||||
Reference in New Issue
Block a user