Commit Graph

44 Commits

Author SHA1 Message Date
sergio b3278bdb0c feat(charka): E/S de ficheros — SELECT/FD/OPEN/READ/WRITE/CLOSE
El gran hueco que faltaba para el COBOL real: el procesamiento de
ficheros secuenciales. Una rebanada vertical por los seis crates.

- charka-parser: la ENVIRONMENT division ya no se ignora — se parsea
  FILE-CONTROL (SELECT name ASSIGN TO "ruta"); del FILE SECTION se
  asocia cada FD con su registro 01. Program::files.
- charka-runtime: tipo CobFile — un fichero «line sequential» (cada
  registro una línea). Lectura: carga a memoria. Escritura: acumula y
  vuelca al cerrar.
- charka-ir: Ir::files y los statements Open/Close/Read/Write. READ
  lleva sus bloques AT END / NOT AT END.
- charka-codegen: un campo CobFile por fichero en el struct Program;
  los verbos emiten llamadas al runtime.
- charka-shadow: el intérprete hace E/S de ficheros real.
- Corpus: programa nuevo 18-fichero — escribe tres líneas, las relee
  con READ ... AT END y las muestra. Verificado: el intérprete sombra
  y el crate compilado por scaffold dan la misma salida.

Alcance v1: organización line sequential; sin ficheros indexados ni
relativos, sin FILE STATUS.

Tests: charka-parser 17, charka-runtime 19, charka-ir 30,
charka-codegen 25, charka-shadow 23. fmt + clippy limpios.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 22:47:26 +00:00
sergio f250fd0765 feat(charka): PERFORM ... THRU como rango real de párrafos
PERFORM A THRU C ejecuta A, B y C; antes el transpilador sólo
ejecutaba A (lo marcaba como aproximado).

- charka-codegen: Symbols registra ahora los párrafos en orden con su
  nombre de método; Symbols::build toma el Ir completo.
  paragraph_range(name, thru) da los métodos del rango; emit_perform
  emite la llamada a cada uno.
- charka-shadow: run_paragraph_range ejecuta los párrafos de name a
  thru inclusive.
- Corpus: programa nuevo 17-rangopar (PERFORM PASO-A THRU PASO-C sobre
  tres párrafos). Verificado: el intérprete sombra y el crate
  compilado por scaffold dan la misma salida.

Tests: charka-codegen 24, charka-shadow 22. fmt + clippy limpios.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 22:36:53 +00:00
sergio 82ba0b7a1a feat(charka): SET ... TO TRUE — escribir nombres de condición (88)
La cara de escritura de los nombres de condición de COBOL: si
IF ES-VALIDO los lee, SET ES-VALIDO TO TRUE los escribe.

- IR: Stmt::SetTrue { conditions }.
- Parser: SET cond-1 cond-2 ... TO TRUE. Otras formas de SET
  (índices, TO FALSE) caen a Stmt::Unknown.
- Codegen y shadow: SET cond TO TRUE asigna a su dato padre el valor
  del 88 (un MOVE del valor a la variable).
- Corpus: programa nuevo 16-bandera (cambia banderas de texto y de
  número con SET). Verificado: el intérprete sombra y el crate
  compilado por scaffold dan la misma salida.

Tests: charka-ir 29, charka-codegen 23, charka-shadow 21. fmt +
clippy limpios.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 22:32:08 +00:00
sergio fa65f20206 feat(charka): INITIALIZE — resetear datos y grupos
El verbo de COBOL para volver un dato (o un registro entero) a su
valor por defecto.

- IR: Stmt::Initialize { targets }. El model de charka-ir registra
  ahora los grupos y sus datos elementales (DataModel::groups,
  GroupInfo { name, members }).
- Parser: INITIALIZE name-1 name-2 ...
- Codegen y shadow: cada destino, si es un grupo, se expande a sus
  miembros; cada dato elemental se pone a 0 (numérico) o a espacios
  (alfanumérico); una tabla OCCURS resetea todos sus elementos.
- Corpus: programa nuevo 15-resetear (resetea un grupo y un escalar).
  Verificado: el intérprete sombra y el crate compilado por scaffold
  dan la misma salida.

Tests: charka-ir 28, charka-codegen 22, charka-shadow 20. fmt +
clippy limpios.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 22:28:47 +00:00
sergio 7867d6830e feat(charka): EVALUATE TRUE y rangos WHEN ... THRU
Completa el EVALUATE con sus dos formas que faltaban.

- IR: la rama WhenBranch pasa de values: Vec<Operand> a
  tests: Vec<WhenTest>, donde WhenTest es Value (igualdad), Range
  (WHEN lo THRU hi) o Cond (EVALUATE TRUE WHEN cond).
- Parser: detecta EVALUATE TRUE y entonces cada WHEN parsea una
  condición; en modo valor reconoce WHEN lo THRU hi.
- Codegen y shadow: una prueba Range se traduce a lo <= s <= hi; una
  Cond, a la condición directa.
- Corpus: programa nuevo 14-clasifica (clasifica notas con rangos THRU
  y un EVALUATE TRUE). Verificado: intérprete sombra y crate compilado
  dan la misma salida.

Tests: charka-ir 27, charka-codegen 21, charka-shadow 19. fmt +
clippy limpios.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 22:22:43 +00:00
sergio 2728698f5e feat(charka): INSPECT — contar y reemplazar caracteres
El verbo de COBOL para analizar y limpiar campos de texto.

- IR: Stmt::Inspect { target, op } con InspectOp::TallyingForAll
  (cuenta apariciones y las suma a un contador) y
  InspectOp::ReplacingAll (reemplaza apariciones).
- Parser: INSPECT t TALLYING n FOR ALL lit y
  INSPECT t REPLACING ALL a BY b. Una forma no soportada cae a
  Stmt::Unknown.
- Codegen: TALLYING -> str::matches(..).count(); REPLACING ->
  str::replace.
- Shadow: el intérprete cuenta / reemplaza el texto.
- Corpus: programa nuevo 13-inspeccion. Verificado: el intérprete
  sombra y el crate compilado por scaffold dan la misma salida.

Alcance v1: TALLYING FOR ALL y REPLACING ALL; sin LEADING, FIRST,
CHARACTERS, BEFORE/AFTER.

Tests: charka-ir 26, charka-codegen 20, charka-shadow 18. fmt +
clippy limpios.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 22:17:47 +00:00
sergio 47c49acd47 feat(charka): STRING y UNSTRING — manejo de cadenas
Dos verbos comunes de COBOL para construir y partir cadenas.

- IR: Stmt::StringConcat { sources, into } y
  Stmt::Unstring { source, delimiter, into }.
- Parser: STRING a b DELIMITED BY SIZE INTO t END-STRING y
  UNSTRING s DELIMITED BY d INTO a b c END-UNSTRING.
- Codegen: STRING -> format! concatenado; UNSTRING -> un bloque que
  parte con str::split y reparte los trozos a los destinos.
- Shadow: el intérprete concatena / parte el texto y lo reparte.
- Corpus: programa nuevo 12-cadenas. Verificado: el intérprete sombra
  y el crate compilado por scaffold dan la misma salida.

Alcance v1: STRING con DELIMITED BY SIZE (otros delimitadores se
ignoran); sin WITH POINTER ni ON OVERFLOW.

Tests: charka-ir 25, charka-codegen 19, charka-shadow 17. fmt +
clippy limpios.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 22:09:10 +00:00
sergio 3902763daa feat(charka): OCCURS — tablas y referencias con subíndice
Los arrays de COBOL, que antes el transpilador descartaba en silencio.
Una rebanada vertical amplia que atraviesa el pipeline entero.

- Parser: la cláusula OCCURS n [TIMES] se captura en DataItem.
- IR: Operand::Indexed { name, index } — una referencia ELEM(I), con
  subíndice 1-based. Los destinos de los statements pasan de
  Vec<String> a Vec<Operand>, así que se puede escribir a un elemento
  de tabla (MOVE x TO ELEM(I), COMPUTE ELEM(I) = ...). model::Field
  gana occurs: Option<u32>.
- Codegen: un campo OCCURS se emite como Vec<Num>/Vec<Text>,
  inicializado con vec![..; n]; una referencia con subíndice indexa el
  vector (1-based -> 0-based).
- Shadow: en el intérprete todo campo es un vector — un escalar es de
  longitud 1, una tabla de n; las referencias se resuelven a
  (nombre, índice).
- Corpus: programa nuevo 11-tabla (llena una tabla con cuadrados y los
  suma). Verificado: el intérprete sombra y el crate compilado por
  scaffold dan ambos SUMA DE CUADRADOS = 000055.

Alcance v1: OCCURS elemental, una dimensión, subíndice de un operando.
Fuera: OCCURS de grupo, multidimensional, DEPENDING ON.

Tests: charka-parser 16, charka-ir 24, charka-codegen 18,
charka-shadow 16. fmt + clippy limpios.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 22:03:48 +00:00
sergio 28ee1ae260 feat(charka): nivel 88 + modelo de datos compartido en charka-ir
Los nombres de condición de COBOL (IF ES-VALIDO), que antes el
transpilador evaluaba siempre como false. Y, de paso, se elimina la
duplicación de la resolución del modelo de datos.

- charka-ir gana un módulo `model`: resolve_data(&[DataItem]) ->
  DataModel aplana el árbol de datos a campos elementales (Field con
  FieldKind) y a nombres de condición (ConditionName). El Ir lleva
  ahora un campo `model` — la fuente única de verdad sobre la
  clasificación de PICTURE.
- charka-codegen y charka-shadow consumen ir.model en vez de
  reimplementar cada uno la clasificación, el ancho de PICTURE y la
  normalización de VALUE. charka-codegen ya no depende de charka-bcd.
- Cond::Named (un nivel 88) se resuelve a `padre = valor`: el codegen
  emite la comparación, el intérprete sombra la evalúa.
- Corregido: un dato con hijos de nivel 88 antes se perdía como si
  fuera un grupo; ahora se reconoce como campo elemental.
- Corpus: programa nuevo 10-condicion (semáforo con 88 de texto y de
  número). Verificado: intérprete y crate compilado dan igual salida.

Tests: charka-ir 23, charka-codegen 17, charka-shadow 15. fmt +
clippy limpios.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 21:50:06 +00:00
sergio 4df7478b71 feat(charka): EVALUATE — el case de COBOL
EVALUATE atraviesa el pipeline entero — antes el parser lo guardaba
crudo como Stmt::Unknown.

- IR: Stmt::Evaluate { subject, whens, other } con
  WhenBranch { values, body }. Varios WHEN apilados comparten cuerpo;
  WHEN OTHER es el caso por defecto.
- Parser: EVALUATE subject WHEN v1 WHEN v2 ... [WHEN OTHER ...]
  END-EVALUATE.
- Codegen: lo baja a una cadena if / else if / else — una rama se
  elige si el sujeto es igual a alguno de sus valores, sin caída.
- Shadow: el intérprete evalúa el sujeto y ejecuta la primera rama
  cuyos valores casen, o el WHEN OTHER.
- Corpus: programa nuevo 09-evaluar (EVALUATE por valor anidado en un
  PERFORM VARYING, con WHEN apilados y WHEN OTHER). Verificado: el
  intérprete sombra y el crate compilado por scaffold dan la misma
  salida.

Alcance v1: EVALUATE por igualdad de valor; no la forma EVALUATE TRUE
con condiciones ni los rangos THRU.

Tests: charka-ir 19, charka-codegen 16, charka-shadow 14. fmt +
clippy limpios.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 21:37:28 +00:00
sergio 321e6f8e27 feat(charka): PERFORM VARYING — el bucle con variable de control
El bucle más usado de COBOL, que antes el parser degradaba a un
PERFORM vacío (un hueco de corrección real). Ahora atraviesa el
pipeline entero como una rebanada vertical.

- IR: PerformControl::Varying { var, from, by, until }.
- Parser: reconoce PERFORM VARYING var FROM x BY y UNTIL cond en
  línea (END-PERFORM) y fuera de línea (PERFORM párrafo VARYING ...).
- Codegen: emite var = from; while !(until) { cuerpo; var += by; }.
- Shadow: el intérprete inicializa la variable, evalúa la condición
  antes de cada vuelta e incrementa al final.
- Corpus: programa nuevo 08-varying (suma 1..10). Verificado: el
  intérprete sombra y el crate compilado por scaffold dan ambos
  SUMA 1 A 10 = 00055 — las dos rutas concuerdan.

Tests: charka-ir 18, charka-codegen 15, charka-shadow 13. fmt +
clippy limpios.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 21:33:14 +00:00
sergio b052c41e3c feat(charka): CLI del transpilador — transpile / scaffold / run / check
App nueva crates/apps/charka — el binario `charka`, que vuelve usable
el pipeline COBOL->Rust desde la terminal.

- transpile <in.cob> [-o out.rs] — emite el código Rust.
- scaffold <in.cob> -o <dir> — genera un crate Rust completo
  (Cargo.toml + src/main.rs) que depende de charka-runtime y compila.
- run <in.cob> — ejecuta el programa con el intérprete sombra, sin
  compilar nada, y muestra su salida.
- check <in.cob> -e <esperado> — ejecuta y diferencia contra una
  salida esperada; reporta las líneas que difieren.

Avisa de los verbos COBOL que aún no se transpilan. Verificado de
punta a punta contra el corpus: scaffold de 06-nomina genera un crate
que compila y produce la misma salida que el intérprete sombra — las
dos rutas de ejecución concuerdan.

4 tests; fmt + clippy limpios.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 21:28:36 +00:00
sergio 4d9ce11b1e feat(charka): charka-shadow — validador en sombra + corpus COBOL
El pipeline COBOL->Rust queda completo (7 crates) y validado de punta
a punta.

charka-shadow certifica que el transpilador preserva la semántica del
COBOL original con una ejecución sombra: un intérprete que corre el Ir
directamente sobre charka-runtime, sin compilar nada. Es una segunda
ruta de ejecución, independiente del código que emite charka-codegen
— si la sombra y el transpilado divergieran, sería un bug.

- interpret(&Ir) -> Outcome ejecuta el IR y captura las líneas de
  DISPLAY; run_source(&str) corre el pipeline completo.
- Tope de pasos (Halt::StepLimit): un bucle que no termina se corta
  en vez de colgarse.
- Módulos: field (datos -> campos vivos) / interp (el motor).

Corpus nuevo crates/modules/charka/corpus/ — 7 programas COBOL de
complejidad graduada (01-hola .. 07-clasificar) con sus salidas
esperadas verificadas a mano: DISPLAY, aritmética con GIVING,
IF/ELSE, PERFORM TIMES/UNTIL, grupos, COMPUTE con paréntesis,
ROUNDED, IF anidado con AND. Material de prueba del pipeline entero.

11 tests (los 7 del corpus + fuente vacío, STOP RUN, tope de pasos,
error de léxico); fmt + clippy limpios.

No hay GnuCOBOL en la máquina: la referencia v1 es el corpus; un modo
futuro diferenciará contra el compilador real.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 21:23:07 +00:00
sergio e52b3fb572 feat(charka): charka-codegen — emisión de Rust desde el IR
La etapa final del transpilador. generate(&Ir) -> String produce un
fuente Rust (un main.rs) que, compilado contra charka-runtime, ejecuta
la lógica del programa COBOL.

- struct Program con un campo Num/Text por dato elemental; new() lo
  inicializa desde las cláusulas VALUE.
- Un método p_<párrafo> por párrafo del PROCEDURE; run() los encadena
  en orden (el «caer» de COBOL); main() construye y corre.
- Cada Stmt -> código Rust: MOVE->.store/.fill, DISPLAY->println!,
  COMPUTE y aritmética -> expresiones Decimal, IF->if/else,
  PERFORM-> llamada / for / while, STOP RUN->process::exit.
- Tolerante: lo no transpilable (Stmt::Unknown, dato sin resolver, **)
  se emite como comentario // charka: — el código generado compila.
- Saneado de identificadores COBOL->Rust (choques con keywords).
- Verificado de punta a punta: un programa COBOL demo transpila a Rust
  que compila contra charka-runtime y produce la salida esperada.
- Módulos: emit / sym / expr / stmt. 14 tests; fmt + clippy limpios.

El pipeline COBOL->Rust corre de punta a punta. Falta sólo
charka-shadow (validador en sombra).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 20:36:26 +00:00
sergio 85156c1509 feat(charka): charka-runtime — soporte de ejecución (campos Num y Text)
El soporte que los programas COBOL transpilados enlazan. charka-codegen
emitirá Rust que llama a esta biblioteca, no Rust autónomo.

- Num: campo numérico (PIC 9(5)V99) — un Decimal conformado a su
  Picture. store trunca a la escala declarada, store_rounded redondea;
  al desbordar la parte entera conserva los dígitos de bajo orden (el
  ON SIZE ERROR de COBOL sin cláusula). display da los dígitos con
  relleno de ceros y signo.
- Text: campo alfanumérico (PIC X(n)) de longitud fija — store
  justifica a la izquierda y rellena/trunca; fill mueve figurativas.
- cobol_text_cmp: comparación alfanumérica con relleno de espacios.
- Reexporta Decimal/Picture/Rounding de charka-bcd.

Construido antes que charka-codegen (la nota de orden del plan los
listaba al revés): el codegen emite contra esta API. 17 tests; fmt +
clippy limpios.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 20:27:28 +00:00
sergio 71a4068d12 feat(charka): charka-ir — representación intermedia con statements tipados
Tercera etapa del transpilador: Program -> Ir. El PROCEDURE division
pasa de sentencias con tokens crudos a un árbol de instrucciones
tipadas.

- lower(&Program) -> Ir: total y tolerante, nunca falla. La DATA
  division pasa tal cual y sirve de tabla de símbolos.
- Stmt cubre MOVE, DISPLAY, ACCEPT, COMPUTE, ADD, SUBTRACT, MULTIPLY,
  DIVIDE, IF/ELSE/END-IF, PERFORM (fuera de línea, en línea, TIMES,
  UNTIL), GO TO, STOP RUN, GOBACK, EXIT, CONTINUE.
- Expresiones de COMPUTE con precedencia y paréntesis (Pratt).
  Condiciones con comparadores símbolo/palabra, AND/OR/NOT y nombres
  de condición (nivel 88).
- Delimita statements por palabras frontera (COBOL no los separa con
  un símbolo). Verbo no soportado -> Stmt::Unknown con tokens crudos.
- Módulos: ast / kw / cursor / expr / stmt. 17 tests; fmt + clippy
  limpios.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 20:23:19 +00:00
sergio d3cdbb2d2d feat(charka): charka-parser — COBOL'85 (subconjunto) a AST
Segunda etapa del transpilador: Vec<Token> -> Program. Alcance v1 = el
esqueleto del programa.

- parse(&[Token]) -> Result<Program, ParseError>. AST: Program
  (program_id, data, paragraphs), DataItem, Paragraph, Sentence.
- Particiona el flujo en las 4 divisions por sus encabezados; extrae el
  PROGRAM-ID de la IDENTIFICATION.
- DATA division -> árbol de DataItem: nivel, nombre, PICTURE
  reensamblado (S9 ( 5 ) V99 -> S9(5)V99) y VALUE. Anida por número de
  nivel (01/77 raíces, 88 cuelga del precedente).
- PROCEDURE division -> Vec<Paragraph> con Sentence de tokens crudos
  (sin parseo de statement). Sentencias previas al primer encabezado
  van a un párrafo implícito "".
- Tolerante: salta SECTION, FD/SD y cláusulas que no sean PIC/VALUE.
- 15 tests verdes; fmt + clippy limpios.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 20:04:00 +00:00
sergio ab56b35e9f feat(charka): charka-lexer — tokenizador de COBOL
Primera etapa del transpilador COBOL→Rust (Fase D del plan macro):
texto COBOL → secuencia de Token. Lexer deliberadamente tonto (emite
Word para todo identificador, la clasificación es del parser). Tokens
Word/Number/String/Period/Symbol con línea+columna; soporta formato
fijo (tarjeta de 80 columnas) y libre; comentarios, comillas dobladas,
operadores de 1 y 2 caracteres. LexError tipado. 17 tests; clippy
limpio. Limitación v1: sin continuación de literales entre líneas.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 19:54:54 +00:00
sergio c56ef25546 feat(nakui): Fase 7 del ERP — pulido (cierra el plan maestro)
Validación inline: al fallar un submit por campos required vacíos, el
form los marca (label destructivo + mensaje debajo), no sólo un toast.
MetaApp.form_errors + validate_required_fields. Secciones de formulario:
FieldSpec.section agrupa campos bajo encabezados; abrir_form del CRM las
usa. Campos condicionales y pulido puramente visual: scope-out conciente.

El plan docs/nakui-erp-masterplan.md queda completo (7/7 fases). Tests
verdes (meta-schema 16, meta-runtime 70, meta-form 8, nakui-ui 14);
clippy limpio en las libs.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 19:43:44 +00:00
sergio b13486e240 feat(nakui): Fase 6 del ERP — export CSV de listas
Toda vista de lista gana un botón «⬇ CSV» que exporta las filas
filtradas/ordenadas (con refs resueltas y montos formateados) a un
archivo <entity>-<timestamp>.csv. Serializador to_csv (RFC 4180, con
escape) en el módulo nuevo meta-runtime/csv.rs. Refactor:
list_filtered_sorted extraído como helper compartido entre el render
de la lista y el export.

Tests de to_csv; meta-runtime 70 + meta-form 8 verdes, clippy limpio.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 19:32:48 +00:00
sergio ab2b8f6638 feat(nakui): Fase 5 del ERP — tablero de KPIs
View::Dashboard: grilla de tarjetas de agregados. Metric Count/Sum/
GroupBy con filtro opcional (CardFilter), computado por compute_metric
en meta-runtime (MetricResult Scalar/Breakdown). meta-form render_dashboard
pinta cada tarjeta con el número grande formateado o un breakdown con
barras de texto. El CRM gana una vista «Panorama»: clientes,
oportunidades, pipeline, ganadas, y breakdowns por etapa y canal.

Tests de compute_metric; verificación del panorama en nakui-ui. Clippy
limpio en las libs.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 19:29:27 +00:00
sergio ab1cf9998a feat(nakui): Fase 4 del ERP — listas profesionales (orden/búsqueda/página)
Las vistas de lista de meta-form ganan: orden por columna (clic en
header cicla asc→desc→off con indicador ▲/▼), búsqueda en vivo (caja 🔍
que filtra por search_in mientras se teclea, vía cx.observe del
TextInput) y paginación (25/página, controles ◀▶). Sin cambios de
schema: son estado del widget. Helpers puros cmp_values (meta-runtime)
y next_sort con tests.

Tests verdes (meta-runtime 63, meta-form 8); clippy limpio.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 19:20:15 +00:00
sergio 6588d0ed6c feat(nakui): Fase 3 del ERP — ficha de detalle
View::Detail: ficha de un record con sus campos + listas de records
relacionados (RelatedList, back-references por via_field) + botones
Volver/Editar. ListView.row_detail enlaza lista→ficha con un botón 👁
por fila; Module::validate exige que apunte a una vista detail. En
meta-form: render_detail/render_related + select_detail con retorno.

El CRM: 👁 en Clientes y Oportunidades abre su ficha; la del cliente
lista sus oportunidades e interacciones. Tests en meta-schema y
nakui-ui verdes; clippy limpio.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 19:12:26 +00:00
sergio eba629a806 feat(nakui): Fase 2 del ERP — relaciones legibles + formato
Column.ref_entity resuelve un UUID al label del record referido;
Column.format (ValueFormat Number/Currency) agrupa miles y prefija
símbolo. El campo entity_ref en formularios muestra el record elegido
por su label, no el UUID. human_label_for_record reconoce nombre/titulo
(español). El módulo CRM: las listas muestran el nombre del cliente y
monto como $12,000.

Helper format_value en meta-runtime. Tests en meta-schema, meta-runtime
y nakui-ui verdes; clippy limpio.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 19:05:04 +00:00
sergio 86d06da020 feat(nakui): Fase 1 del ERP — FieldKind Select + AutoId, seed inyecta id
Primera fase del plan maestro. La metainterfaz gana dos tipos de campo:
Select (chips de un conjunto cerrado, con options validadas) y AutoId
(UUID autogenerado read-only). NakuiBackend::seed inyecta el id de la
entity = clave del store. El módulo CRM los adopta: etapa/canal son
selects, los ids de idempotencia se autogeneran, el form de cliente ya
no pide id. Ningún formulario pide un UUID a mano.

Tests en meta-schema, meta-runtime y nakui-ui verdes.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 18:55:13 +00:00
sergio 0d1e378e42 docs(nakui): plan maestro del ERP profesional
7 fases ordenadas por dependencia e impacto para llevar nakui de
"listas y formularios que funcionan" a ERP terminado: captura sin
fricción, relaciones legibles, ficha de detalle, listas profesionales,
tablero/KPIs, reportes, pulido. Más estado actual y criterios de
"terminado".

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 18:55:13 +00:00
sergio e187ab4cd3 feat(nakui-ui): CRM como ERP — UiModule con listas y formularios
examples/nakui-modules/crm/module.json: el módulo crm se ve ahora como
un ERP en nakui-ui (sidebar + listas + formularios), no sólo como el
timeline del event log. 7 vistas — lista+form de Clientes, Oportunidades
e Interacciones — con los formularios de morfismo Abrir/Mover/Registrar
que disparan los morfismos reales del kernel (nakui_module_dir engancha
el módulo crm). 2 tests verifican parseo, validación y carga por el
camino brahman_cards.

Correr: NAKUI_MODULES_DIR=examples/nakui-modules cargo run -p nakui-ui

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 18:35:35 +00:00
sergio 78fbde12b4 feat(nakui): módulo crm — clientes, pipeline de ventas, interacciones
Módulo CRM declarativo (schema.ncl + nsmc.json + morfismos Rhai) con
tres entities (Cliente, Oportunidad, Interaccion) y tres morfismos:
abrir_oportunidad, mover_oportunidad (pipeline con validación de
transiciones) y registrar_interaccion.

crm_demo: demo realista de 18 eventos que —a diferencia de los otros
demos— conserva el event log e imprime el comando de nakui-explorer,
así el explorador muestra un CRM con cuerpo. tests/crm.rs: 8 tests.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 18:21:09 +00:00
sergio bb21c28eb1 feat(mirada): mirada-greeter — greeter de login del escritorio carmen
App GPUI con app_id carmen.greeter: formulario usuario+contraseña que
autentica con brahman-auth en un hilo de fondo y, en éxito, emite un
SessionTicket por stdout para que el compositor haga el traspaso a modo
sesión. Backend mock (MIRADA_GREETER_MOCK) o PAM.

Incluye brahman-auth::SessionTicket (contrato de tiquet greeter→compositor,
serializado a una línea con prefijo versionado) y el modo enmascarado de
nahual-widget-text-input (TextInput::with_mask para contraseñas).

18 tests nuevos; greeter verificado por compilación + clippy.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 17:59:12 +00:00
sergio 8a15b812f9 feat(auth): brahman-auth — autenticación del escritorio (PAM + mock)
Base del DM/greeter de carmen. Contrato Authenticator agnóstico:
authenticate(usuario, secreto) -> UserInfo (uid/gid/home/shell).
PamAuthenticator verifica contra PAM (/etc/pam.d/carmen); MockAuthenticator
con credenciales en memoria para tests. AuthError grueso: BadCredentials
vs AccountUnavailable, sin filtrar existencia de cuentas. resolve_user
vía getpwnam. data/carmen como servicio PAM; ejemplo auth-probe.

11 tests; el camino PAM real se ejercita.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 17:47:05 +00:00
sergio af3be482a9 feat(theme): exportación a GTK + inyección de entorno en el compositor
Segunda mitad de la uniformización del tema. nahual-theme::toolkit
traduce el Theme activo a gtk-3.0/gtk.css y gtk-4.0/gtk.css con overrides
@define-color (acento exacto + neutro claro/oscuro sintetizado).
Theme::set/install_default exportan best-effort; guarda de no-pisar
respeta un gtk.css ajeno. El compositor inyecta XDG_CURRENT_DESKTOP=mirada
y QT_QPA_PLATFORMTHEME=gtk3 a cada hijo, así GTK y Qt siguen el tema.

8 tests nuevos en toolkit; ejemplo dump-toolkit-css.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 17:41:35 +00:00
sergio 5369c307e4 feat(mirada): mirada-portal — backend de tema org.freedesktop.appearance
Backend de xdg-desktop-portal para carmen: implementa
org.freedesktop.impl.portal.Settings y publica color-scheme,
accent-color y contrast desde el tema activo de nahual. GTK4, Qt6,
Firefox y Chromium voltean claro/oscuro + acento por protocolo, sin
tocar sus configs. Watcher con notify del archivo de nahual-theme →
emite SettingChanged en vivo. 13 tests; smoke verificado sobre un bus
de sesión efímero.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 16:05:27 +00:00
sergio 7dc533dbbf docs(status): matilda — 7 crates + CLI, módulo funcional
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-20 20:32:01 +00:00
sergio 2b340fdf40 docs(status): registra charka y mirada
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-20 17:25:02 +00:00
sergio 9e7fa17411 docs(status): registra matilda y yachay
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-20 17:09:31 +00:00
sergio 71f6cf1306 docs(status): registra dominium, verbo, agorapura, badu, takiy; fana al día
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-20 16:46:56 +00:00
sergio b83d40a833 refactor(naming): A1 — ente→arje, vista→revista, pluma→fana
Rename batch de la Fase A del PLAN_MACRO:
- 25 crates ente-* → arje-* (protocol/init/runtime/compat). El linaje
  arje (init Linux) queda con prefijo coherente.
- vista → revista (revista-core + revista-web).
- pluma → fana (fana-md + fana-md-reader-web). fana absorbe el linaje
  markdown de pluma; será el writer DAG editor (prioridad alta).

Cambios:
- git mv de 29 crate dirs + 2 SDDs
- package/lib/bin names + path refs + imports .rs reescritos
- workspace Cargo.toml + comentarios de sección
- SDDs de init/runtime/compat/protocol actualizados a arje-
- SDD de revista + SDD de fana (reescrito: writer DAG editor)
- docs/STATUS.md, ROADMAP.md, PLAN_MACRO.md, arje-boot.md,
  arje-replace-systemd.md actualizados
- docs/changelog/akasha.md → chasqui.md

scripts/rename-fase-a.py idempotente (--dry-run soportado).
cargo check --workspace verde.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-20 00:10:14 +00:00
sergio 3fc6dcfa72 docs: PLAN_MACRO.md — plan de ejecución global del ecosistema
Compilación del input de planificación recibido el 2026-05-19:
21 módulos totales (12 existentes + 9 nuevos + 1 rename), 6 servicios
compartidos como libraries horizontales, ~60-110K LOC nuevo código.

Estructura del plan:
- Fase A (sem 1-2): foundations cleanup (rename, brain split, lifecycle
  extract, pivot_root+overlayfs, transport-ssh)
- Fase B (sem 2-5): core libraries (sandokan, dime, discovery-dht)
- Fase C (sem 4-12): apps standalone paralelos (carmen, akashi, matilda,
  takiy, dominium, ágora)
- Fase D (multi-mes): charka outlier (parser COBOL completo)
- Fase E (sem 12-18): yachay integrador
- Fase F (continuo): cobertura tests + cerrar stubs cosmo/pineal
- Fase G (post): backlog (rimay, yuyay, apu, tinkuy, nutu + 4)

Critical path: 17-23 semanas (4-5.5 meses) sin charka completo.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-19 19:57:44 +00:00
sergio e570c6ca6f docs: fix factual errors en SDDs y STATUS/ROADMAP
Errores detectados al auditar afirmaciones técnicas contra el código:

1. minga-vfs: NO está relacionado con Mónadas (esas son de akasha).
   Es FUSE que proyecta el índice de minga (git semántico) como
   filesystem, resolviendo paths virtuales a blobs por hash.

2. protocol/SDD.md: Card tiene 19 campos, no 6. Añadido bloque con
   anatomía completa del struct.

3. STATUS.md: LOC por capa corregidos contra wc -l real
   - protocol: 6,260 → 7,278
   - init:     ~3,600 → 4,301
   - compat:   ~5,000 → 3,435 (estaba sobrestimado)

4. pineal: 6 stubs (<30 LOC c/u), no 5. Export (23 LOC) también es
   stub funcional. LOC reales por sub-crate documentados.

5. init/SDD.md: ente-soma es wrapper de 44 LOC, no ~30.

6. akasha/SDD.md: fastembed está detrás de feature `embeddings`,
   ort es transitivo. Sin feature, akasha-nous-real es stub mínimo.

7. vista/barra: LOC ajustados (vista-core 177, barra-core 108).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-19 17:03:05 +00:00
sergio 550c98f275 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>
2026-05-19 14:48:34 +00:00
sergio ca5dd04176 feat(arje): reemplaza systemd en máquina real con coexistencia GRUB
Flujo seguro de adopción: arje se instala como entrada GRUB
alternativa, no toca systemd ni /sbin/init. Booteás arje cuando
querés, volvés a systemd si rompe (rollback instantáneo desde el
menú).

Artefactos nuevos:

- scripts/install-arje-as-init.sh: instala binarios musl-static a
  /usr/sbin/ y /usr/bin/, copia seed a /ente/seed.card.json, agrega
  menuentry "arje" a /etc/grub.d/40_custom usando init=/sbin/ente-zero
  con kernel + initrd nativos. NO cambia GRUB_DEFAULT. Idempotente
  (regenera el bloque ARJE-MENUENTRY si existe).

- scripts/uninstall-arje.sh: revierte binarios + menuentry. Conserva
  /ente/seed.card.json por si la editaste.

- seeds/arje-host.card.json: seed para máquina real con 15 cards:
  tmpfiles + mount-fstab + swap-on + dbus-system + 11 compat shims +
  dhcpcd + sshd + agetty. Validada.

- docs/arje-replace-systemd.md: filosofía vs systemd ("no acapara
  porque no genera, sólo arranca lo declarado"), lista exhaustiva de
  servicios systemd que NO deben migrarse (ModemManager, snapd, cups,
  unattended-upgrades, etc.), tabla diferencial de UX vs systemd
  (systemctl restart → kill PID, systemctl enable → editar seed),
  checklist pre-primer-boot, instrucciones de rollback y cómo hacer
  arje default sólo cuando estés seguro.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-18 20:01:12 +00:00
sergio e4b1d41b62 feat(arje): incluye CLIs admin en el initrd (brahman-status/busctl/brainctl)
Para "ver" la administración del init desde el shell que arrancó dentro
del initramfs hacían falta clientes que hablen los 4 sockets Unix. Los
exists como examples de cada crate; los empaquetamos ahora.

build-arje-initrd.sh:
- cargo build --example brahman-status -p brahman-admin
- cargo build --example busctl         -p ente-bus
- cargo build --example brainctl       -p ente-brain
- Copia los 3 a /usr/bin/ del initrd.

docs/arje-boot.md §6b reescrita con:
- Tabla de sockets corregida (defaults a /tmp/ cuando no hay
  XDG_RUNTIME_DIR/TMPDIR, que es el caso en initrd).
- Cookbook de los 3 CLIs con ejemplos de sesión típica dentro de la VM.
- Nota para vendorear socat-static via EXTRA_BINS si querés conectar
  crudo a un socket.

§1 layout actualizado con /usr/bin/{brahman-status,busctl,brainctl}.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-18 19:42:29 +00:00
sergio ec458b8a6f fix(arje): build-initrd compila musl-static por default
Sin musl, PID 1 panic con "error while loading shared libraries:
libgcc_s.so.1" porque el initramfs no incluye libgcc/glibc/ld-linux.
Solución estándar: target x86_64-unknown-linux-musl produce un ELF
totalmente estático.

Cambios en scripts/build-arje-initrd.sh:
- ARJE_TARGET=x86_64-unknown-linux-musl por default (override con env).
- Chequeo del target instalado antes de buildear; mensaje accionable
  con los comandos exactos (rustup target add..., apt install
  musl-tools, etc.) si falta.
- Sanity check con `file`: aborta si ente-zero quedó dinámico.
- Sanity check para busybox: aborta si el BUSYBOX_BIN apunta a un
  binario dinámico (la otra causa #1 de panic).
- BIN_DIR ahora apunta a target/$TARGET/release/.

Docs (docs/arje-boot.md):
- §2a explica el porqué de musl.
- §2b lista requisitos del host (rustup target, musl-tools, busybox-static).
- §7 sección nueva de troubleshooting con el síntoma exacto del
  libgcc_s panic + 3 escenarios comunes más.
- Checklist pre-deploy actualizado con el chequeo de "statically linked".

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-18 19:17:52 +00:00
sergio 8592bab19e docs(arje): organiza core/ + seeds canónicas + boot reproducible
- crates/core/README.md: agrupamiento lógico de los 31 crates absorbidos
  de arje (ente-*) y del protocolo brahman (brahman-*) en 6 grupos —
  Init/PID 1, contratos, discovery, IPC+CAS, cerebro, 14 shims compat
  systemd. No se movieron crates físicamente (rompería paths
  cross-workspace).

- seeds/arje-minimal.card.json: PID1 + /bin/sh, smoke test QEMU.
- seeds/arje-prod.card.json: PID1 + 14 shims compat + tmpfiles/binfmt
  one-shots + echo + getty (16 children). Validados con
  brahman_card::Card::validate.
- seeds/validate.sh: carga la seed vía ente-zero en dev mode.

- scripts/build-arje-initrd.sh: empaqueta CPIO+gzip newc layout
  /init→/sbin/ente-zero, /usr/sbin/ente-*-compat, /ente/seed.card.json,
  /bin/{sh,...} (busybox o glibc+ldd). Tested: produce 20 MB initrd OK.
- scripts/run-arje-qemu.sh: qemu-system-x86_64 con KVM auto-detect,
  -kernel/-initrd/-append "rdinit=/init console=ttyS0,115200 panic=10".

- docs/arje-boot.md: doc end-to-end — layout initramfs, QEMU (con kernel
  del host o externo), GRUB bare metal, Proxmox/libvirt args:, schema
  de Card con todas las validaciones, debugging (sockets de
  introspección, snapshot/restore, metrics), checklist pre-deploy.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-18 18:40:05 +00:00