- Changed install_deck_delegation → install_controls_delegation:
listener on document, not just #deck (controls are outside deck now)
- Graph node click: use dyn_into::<HtmlElement>() then click() instead
of dyn_ref which may fail on <a> elements
- .page-controls visibility: changed from (wrong) to
- Graph node callback: use HTMLElement.click() instead of
dispatch_event(MouseEvent), which wasn't working (untrusted event)
- Moved the minimize/close buttons from dynamic JS creation to
static HTML in index.html (always present, hidden by default)
- sync_page_controls() now just toggles opacity/pointer-events
instead of creating DOM elements
- Graph callback now creates a web_sys::MouseEvent('click') and
dispatches it on the corresponding .tip element.
- The existing install_tip_clicks listener captures it and calls
open_or_switch with proper coordinates.
- Changed all relative paths (./styles.css → /styles.css,
./pkg/gioser_web.js → /pkg/gioser_web.js,
./md/*.md → /md/*.md) to absolute so they don't break when
pushState changes URL to /estudio/aire etc.
- Caddy already has try_files fallback to /index.html for SPA routing.
- Graph: nodes are draggable via pointer events. Snap back with
spring transition on release (cubic-bezier 0.34,1.56,0.64,1)
- Removed hover bounce animation (was distracting)
- Page controls (minimize/close): now fixed position in viewport
(top-right, z-index 100), not inside the deck-page scroll area.
Created once in sync_page_controls() on show/hide deck.
Controls detect active page when data-minimize/close-page is empty.
- Hash routing → history.pushState: URLs are /estudio/aire etc.
popstate listener handles back/forward. Initial path read on boot.
- Added PointerEvent feature to gioser-graph-web Cargo.toml
- Added History feature to gioser-web Cargo.toml
- Edges and nodes now in separate SVG <g> groups (edges first = behind)
- Stroke width: 0.6 + w*4.0 instead of normalized range (more visible variation)
- Brightness: uses raw weight directly, not normalized against max
- Edges group has no breathing animation (only nodes breathe)
- Each edge color is a 50/50 blend of its two nodes' camino colors
- Extra brightness proportional to weight (higher weight = closer to white)
- Edge opacity/width also varies by weight
- Edges drawn before nodes in SVG (already behind them)
- Fix: map positions by node.id (UUID) not doc_id — edges now draw
- Index the 4 docs/ files into Qdrant (15 fragments via index-gioser-docs.py)
- Page background: single smooth radial-gradient per element (no color
divisions), animated 'page-breathe' — opacity pulses 0.35↔0.80
- Graph CSS: 'graph-breathe' 5s opacity animation (feels alive)
- Uses setInterval(50ms) waiting for offsetWidth > 0
- Falls back to minWidth/minHeight after 10s timeout
- Solves 'cannot access property w' when deck is hidden (scale 0)
- Wraps the entire fetch+render in requestAnimationFrame
so the container has real size before Cytoscape runs cose layout
- Uses 'preset' layout first, then cose with animate:'end'
to play nice with 0-size containers during deck animation
- cytoscape-graph.js now uses MutationObserver, not DOMContentLoaded
(the <gioser-graph> element is created dynamically by WASM)
- Remove unused dispatchEvent from lib.rs
- Rebuild WASM
- Switch from circles to horizontal rounded rectangles with text inside
- Text size 12px body + 8px sublabel (camino), no overlaps
- Edge stroke-width proportional to semantic weight
- Fix 'Layout was forced' warning
- Reduce CSS page-ambience animations: only opacity (no transform)
to fix 'breathing background' visual glitch
- Layout: more separation (k*1.6), 80 iterations
- Add gioser-graph-web dependency to gioser-web
- After markdown loads, mount SVG semantic graph below content
- Graph fetches from api.gioser.net/graph endpoint
- Uses Qdrant k-NN edges, colored by camino
- Callback navigation placeholder (will be wired in next commit)
El rectificador deja la aproximación y pasa a la trigonometría exacta,
con precisión de segundo — el "microajuste argentino".
LA MATEMÁTICA. El rectificador ya NO usa el modelo simplificado
(directed_longitude, rotación uniforme de RA + convergencia GR). Ahora
usa `eternal_astrology::primary_direction::all_directions` — el método
Placidus-mundano: semi-arcos diurnos/nocturnos bajo el polo de cada
cuerpo, la trigonometría esférica de la escuela ascensional. No se
reimplementó nada: la matemática, ya probada, vive en eternal; el
engine sólo aporta la capa de optimización.
- error_de_carta: por cada evento, la distancia en años a la dirección
primaria que perfecciona más cerca; el error total es la suma. Es la
función de coste del microajuste — el valle es la hora real.
PRECISIÓN DE SEGUNDO. compute_natal_chart / build_eternal_inputs /
natal_cache pasan a trabajar en SEGUNDOS (compose convierte ×60). El
rectificador barre en dos pasadas: gruesa minuto a minuto sobre la
ventana (el perfil que dibuja la curva), fina segundo a segundo en
±60 s alrededor del mejor minuto.
- Rectificacion: mejor_offset_segundos; el perfil va en segundos.
- UI: panel y curva muestran «±Xm Ys · error N.NNa». Las barras siguen
siendo clicables (scrub a esa hora candidata).
Tests verdes (engine 12, render 28). Limitación conocida: all_directions
es sólo directo — converso necesita crecer en eternal (upstream).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Tercer y último incremento: la visualización. El rectificador ya
muestra POR QUÉ una hora gana, no sólo cuál.
- cosmobiologia-canvas: CanvasState gana `rectificacion` +
`set_rectificacion`. render_rectify_profile dibuja el barrido como
un histograma en el footer — cada barra es una hora candidata, su
altura crece cuanto menor el puntaje; la barra más alta (el valle
del puntaje) es la hora rectificada, resaltada. Etiqueta los hitos
(mejor, 0, extremos).
- shell: run_rectificacion publica el Rectificacion al canvas además
del resumen textual al panel.
Con esto el rectificador automático (#67) queda completo: motor de
escaneo GR + UI de entrada + visualización del perfil.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Segundo incremento: el rectificador ya es usable de punta a punta
desde el panel, sin infraestructura de UI nueva.
- cosmobiologia-panel: Control::TextInput pasa a renderizarse desde
string_state — deja de ser un display estático y se vuelve un campo
de sólo-lectura que el shell escribe vía set_string (resultados,
etiquetas).
- cosmobiologia-modules: el módulo primary_directions gana 3 sliders
«Evento N · edad» (0 = ranura sin usar), un Action «Rectificar
hora» y un TextInput «Resultado».
- shell: run_rectificacion lee las edades de los sliders, llama a
engine::rectificar (ventana ±15 min, paso 1) y escribe la hora
rectificada + el puntaje en el campo Resultado del panel.
El rectificador queda funcional: activar GR → fijar edades de eventos
→ «Rectificar hora» → leer el resultado. Falta sólo la curva del
perfil del barrido como visualización (incremento opcional).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Completa la feature de armónicos: además de la carta armónica, ahora
hay un espectro que guía qué armónico mirar.
- cosmobiologia-render: harmonic_spectrum computa la fuerza de cada
armónica 1-32 (suma de cercanía a conjunción exacta de los pares de
cuerpos en esa armónica). apply_harmonic lo puebla + expone el
armónico activo. Campos RenderModel.harmonic / .harmonic_spectrum.
2 tests nuevos (el pico cae en la armónica resonante).
- cosmobiologia-canvas: render_harmonic_spectrum pinta el histograma
en el footer; cada barra es clicable y emite HarmonicSelected — un
clic salta a esa armónica. La barra activa va resaltada.
- shell: select_harmonic fija el slider del módulo natal y recompone.
- modules: el slider de armónico pasa de 1-20 a 1-32 (rango del
espectro).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
El slider "Armónico" del NatalModule existía pero no hacía nada.
Ahora re-renderiza la carta en el armónico de orden N.
- cosmobiologia-render: módulo `harmonic` agnóstico — apply_harmonic
transforma los cuerpos natales a (longitud·N) mod 360 y recomputa
los aspectos sobre las posiciones armónicas (conjunción, oposición,
trígono, cuadratura, sextil). Las casas se conservan como marco.
6 tests (incluye: quintil natal → conjunción en H5).
- cosmobiologia-engine: NatalOptions.harmonic; compose lo aplica tras
la pasada natal, antes de los overlays. Test end-to-end.
- shell: build_natal_options lee el slider del módulo natal.
El título anota "· HN". Falta: histograma de fuerza por armónico.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Tercer y último incremento del Sistema GR: en modo GR (direcciones
primarias activas) el jog-dial deja de rotar el wheel y pasa a
scrubear la edad en vivo.
- canvas: CanvasState::gr_active() detecta el modo; on_jog_move emite
CanvasEvent::GrAgeDelta (años por grado de jog, sensibilidad 0.1)
en vez de rotar; on_jog_up no aplica snap de tiempo.
- shell: scrub_gr_age acumula el delta sobre target_age_years del
módulo primary_directions, clampa a [0,120], sincroniza el slider
del panel y recompone — los glifos dirigidos y el HUD se mueven en
vivo bajo el cursor.
Con esto el Sistema GR queda completo: cómputo de triggers, resaltado
de convergencias, HUD de rectificación y scrubbing live.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
`mirada-compositor --greeter` arranca como gestor de login: lanza
mirada-greeter como proceso hijo, lee su stdout y, al recibir el
SessionTicket, muta de BodyMode::Greeter a BodyMode::Session sin
reiniciar el servidor Wayland — la «mutación atómica» del DM.
- BodyMode { Greeter, Session }: eje ortogonal a Brain (Embedded/Linked).
- modo greeter: sin atajos registrados, rechaza Spawn, sin autoarranque.
- traspaso (complete_greeter_handoff): registra los atajos y arranca la
sesión — el comando del tiquet, o el autoarranque del usuario.
- privilegios: el compositor corre como root; spawn_command baja a
setuid/setgid + grupos suplementarios del usuario autenticado.
- bandera ortogonal al backend (--greeter [--drm|--winit]); el tiquet
llega por un canal calloop en DRM y por mpsc en winit.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
El formateo de informes de COBOL: supresión de ceros a la izquierda,
coma de millares e inserción del punto decimal. Rebanada vertical.
- charka-lexer: el punto separador exige un espacio detrás; un punto
pegado a un carácter (ZZ9.99) ya no es terminador, sino símbolo —
el parser lo reensambla dentro de la cláusula PICTURE.
- charka-runtime: format_edited(valor, pic) — 9, Z, coma, punto, B.
- charka-ir: Field::edit guarda la PICTURE; el campo es texto.
- charka-codegen / charka-shadow: MOVE a un campo de edición pasa por
format_edited antes de almacenar.
- Corpus: 19-reporte. Sombra y crate compilado dan la misma salida.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
Sólo formato (orden de imports + wrapping), arrastrado por cargo fmt -p
nakui-ui al trabajar en el módulo CRM.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
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>
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>
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>
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>
Fase 3c: el shell muestra la salida de los comandos en un cajón que se
despliega hacia arriba sobre el escritorio.
carmen — la ventana del shell deja de tener un alto fijo: `render_loc`
la ancla al pie de la salida y la coloca por su **tamaño real**, así
puede crecer hacia arriba. La franja reservada sigue siendo la barra
(40 px); el cajón, al abrirse, se solapa sobre las teseladas sin
re-teselar. `render_loc` toma ahora el alto de la salida.
shuma-shell — un clic en el estado alterna `drawer_open`: la ventana
crece (`Window::resize`, que GPUI 0.2 expone) a barra + cajón, o
vuelve a sólo barra. El cajón reusa `render_run` para pintar los
últimos comandos y su salida, con scroll. `render_launcher` pasa a una
columna: cajón opcional arriba, barra abajo.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Fase 3b: la barra del shell muestra ahora las ventanas abiertas del
escritorio y deja saltar entre ellas.
- `shuma-shell` depende de `mirada-brain` para hablar el protocolo de
control de carmen.
- `start_loop` sondea el socket de control cada ~1 s con `ListWindows`
— la llamada bloquea un instante, pero en el executor de fondo, no en
el hilo de la UI. El resultado se guarda en `Shell.windows_bar`.
- `render_launcher` dibuja una cajita por ventana entre el input y el
estado: la enfocada resaltada, las demás en gris. Un clic envía
`Do(FocusWindow(id))` y refleja el cambio al instante (el sondeo lo
confirma en el siguiente ciclo).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>