Commit Graph

5 Commits

Author SHA1 Message Date
sergio a539fab15c feat(tahuantinsuyu): fase 24 — observabilidad del broker brahman
Primera pieza concreta de integración con el fractal brahman. La app
deja de ser standalone visible: ahora muestra el estado del broker
en el header con un badge actualizado cada 30s.

- Shell gana enum BrahmanStatus { Pending, Connected { count },
  Offline { reason } } + field brahman_status.
- spawn_brahman_status_loop arma un task cx.spawn que cada 30s
  invoca brahman_sidecar::list_sessions_blocking sobre el
  background_executor (no UI thread — list_sessions_blocking abre su
  propio tokio runtime, hacerlo en el UI panicearía con "nested
  runtime"). Update via this.update + cx.notify dispara repintado del
  badge.
- header agrega pill "Brahman ✓ N sessions" (color accent cuando
  conectado), "Brahman · offline" (fg_disabled) o "Brahman · …"
  (fg_muted) según el último ping. Entre el separador flex_grow y
  el theme_switcher.
- apps Cargo agrega brahman-sidecar como dep directa.

La Card de tahuantinsuyu (fase 1) sigue declarando los flows
`chart-request` (input) y `chart-result` (output), pero ESTOS NO
ESTÁN CABLEADOS A UN DATA PLANE — solo aparecen en el broker como
declaración. Para que tahuantinsuyu PUBLIQUE/CONSUMA datos reales
(otra app del fractal recibiendo una carta serializada, o pidiendo
un cómputo) hay que:
1) Abrir un service_socket Unix server en el sidecar
2) Implementar protocolo postcard sobre ese socket
3) Otro módulo descubre el socket via broker → conecta y envía/recibe

Eso es una fase separada (25+). Esta fase 24 cubre la observabilidad
mínima: la app sabe que el fractal está vivo y muestra el head count.
Cubre el espíritu del brief inicial ("integrar con yahweh que maneja
gpui para intercomunicar widgets") al nivel de visibility — el data
plane real es un proyecto en sí mismo.

cargo check verde. Sin tests nuevos (la lógica nueva es interacción
UI + background task — los tests serían smoke tests del Shell que
no tenemos).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-17 23:51:22 +00:00
sergio 295c9ba554 feat(tahuantinsuyu): fase 22 — layout splitter + atlas loadable desde XDG
Dos features de producción que mejoran la usabilidad sustancialmente.

## #7 — Layout reorganizable con SplitContainer

Los 3 paneles ya no tienen tamaños hardcodeados. Reusamos
yahweh-widget-splitter (mismo que usa yahweh-shell para sus layouts
JSON-config) con 2 niveles:

- outer (Vertical): main_split arriba (flex 4) + panel abajo (flex 1)
- main_split (Horizontal): tree (flex 1) + canvas (flex 4)

El usuario puede arrastrar los dos divisores para redimensionar
libremente. Por ejemplo: en una pantalla ancha, dar más al canvas; en
una sesión de lectura analítica, agrandar el panel abajo para ver más
módulos expandidos.

- Shell gana fields main_split + outer_split: Entity<SplitContainer>.
- new() construye ambos con ChildSlots envolviendo tree/canvas/panel
  como AnyView (mismo patrón que LayoutHost de yahweh-shell).
- render() simplificado: header + body(outer_split). Las constants
  TREE_WIDTH y PANEL_HEIGHT desaparecen.
- Cargo añade deps: yahweh-core (NodeId, LayoutDirection),
  yahweh-widget-splitter, yahweh-widget-container-core (ChildSlot).

## #15 — Atlas de ciudades cargable desde TSV

El array `CITY_PRESETS` const de 90 ciudades hardcoded ahora es la
función `default_city_presets() -> Vec<CityPreset>`. CityPreset.name
pasa de `&'static str` a `String` para que el atlas sea construible
en runtime.

TahuantinsuyuTree gana `city_atlas: Vec<CityPreset>` + setter
`set_city_atlas(atlas, cx)`. Al boot, Shell intenta cargar
`$XDG_DATA_HOME/tahuantinsuyu/atlas.tsv` y, si existe + parsea bien,
reemplaza el atlas hardcoded.

Formato TSV (líneas):
  name<TAB>lat<TAB>lon<TAB>tz_offset_minutes
  Líneas vacías y `#` comentario se ignoran.
  Líneas con cualquier parse fallido se descartan en silencio.

API pública: `parse_city_atlas_tsv(&str) -> Vec<CityPreset>` (en
tahuantinsuyu-tree), reusable por tests/scripts.

El usuario que quiera 50.000 ciudades de GeoNames cities5000.txt:
1. wget cities5000.zip de geonames.org
2. awk para extraer (name, lat, lon, tz_offset) y escribir TSV
3. mover a $XDG_DATA_HOME/tahuantinsuyu/atlas.tsv
4. relanzar la app

Sin fricción adicional para el usuario común (los 90 hardcoded cubren
99% de casos típicos en español/inglés).

cargo check verde, 8 tests engine + 1 test modules verdes.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-17 23:46:34 +00:00
sergio 32ab22f954 feat(tahuantinsuyu): fase 19 — theme switcher + house tooltips + midpoints + city presets
Fase completa con 4 mejoras independientes que aprovechan toda la
infraestructura previa. La aplicación ahora cubre lecturas profundas
(midpoints uranianos), accesibilidad visual (tooltips de cusps),
personalización (6 themes vía yahweh-widget-theme-switcher) y
usabilidad pragmática (city presets en el form).

## C — Theme switcher en header

- apps/tahuantinsuyu: nueva dep yahweh-widget-theme-switcher.
- shell render(): theme_switcher(cx) en el extremo derecho del header
  (con flex_grow del divider del medio). Click cicla entre los 6
  presets de yahweh-theme (Nebula, Aurora, Sunset, FlatDark,
  SolarizedLight, HighContrast). AstroPalette::for_theme(theme) lee
  is_dark, así toda la rueda se re-tinta automáticamente.

## B — Tooltips sobre house cusps

- canvas: HoverInfo deja de ser struct para ser enum con variantes
  Body { ... } y HouseCusp { house_number, deg, local_x, local_y }.
  Helpers .local() y .key() unifican el acceso.
- on_hover_check: primero hit-test bodies (threshold 14px); si no hubo
  match Y el mouse está dentro del anillo de casas
  (houses_inner..houses_outer ± 6px), calcula la longitud zodiacal
  desde el ángulo de pantalla (inversa de polar_to_screen) y busca el
  cusp más cercano (proximidad angular < 2.5°). HoverInfo::HouseCusp.
- Tooltip render: "Cusp Casa N · Signo XX.X°".

## D — MidpointsModule (Uranian-lite)

- engine: PipelineRequest::Midpoints (sin parámetros, default empty).
- bridge: build_midpoints_overlay computa midpoints entre todos los
  pares de placements donde involucran Sol o Luna (~10 puntos según
  body set). Fórmula: si |a-b|>180, mid=((a+b)/2+180) mod 360, sino
  (a+b)/2 mod 360. Emite como Layer { kind: Midpoints, module_id:
  "midpoints", ring: 0.62 } con Glyph.symbol="sun/jupiter" y
  annotation="Sun/Jupiter".
- modules: midpoints::MidpointsModule con toggle "Activar". Registry
  pasa a 7 módulos. Test actualizado.
- shell: build_requests detecta midpoints.enabled, pushea
  PipelineRequest::Midpoints (no toma age ni body — es derivado puro).
- canvas: Radii agrega midpoints: r * 0.62 (entre houses_inner y
  bodies natales). body_ring("midpoints") y aspect_endpoints retornan
  ese radio. paint_wheel agrega un loop para LayerKind::Midpoints
  pintando dots pequeños (r=0.012, alpha 0.7 sobre house_cusp color)
  — los midpoints no llevan unicode symbol propio (no existe en
  Unicode astrológico estándar). El detalle del par viene en hover.
- Hover sobre un midpoint: tooltip muestra "☉/♄ Tauro 14.3° ·
  Sun/Jupiter" (display_symbol parsea "a/b" en dos unicodes;
  annotation incluye nombres completos eternal).

## A — City presets en el ChartForm

- tree: nueva const CITY_PRESETS con 25 ciudades (Latinoamérica
  capitales + 5 europeas + 5 anglosajonas + Tokyo/Sydney/Mumbai/Cairo)
  con (name, lat, lon, tz_offset_minutes) sin DST. CityPreset struct.
- tree: TahuantinsuyuTree gana city_picker_open: bool. close_modal
  lo resetea. toggle_city_picker + apply_city_preset(preset) helpers.
  apply_city_preset lee el Modal activo (CreateChart o EditChart),
  llama TextInput::set_text en place/lat/lon/tz del ChartForm,
  cierra el picker.
- render_chart_form: title_row ahora tiene "📍 Ciudad rápida ▾"
  button a la derecha del title. Click → toggle. Cuando picker_open,
  popup absoluto debajo con la lista de presets. Click en preset →
  autocompleta + cierra. El usuario sigue pudiendo editar manualmente
  cualquier campo después; el preset es solo un punto de partida
  rápido para evitar tipear coordenadas a mano.

cargo check verde, 8 tests engine + 1 test modules (7 módulos)
verdes.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-17 23:12:17 +00:00
sergio d4761bf238 refactor(tahuantinsuyu): fase 6 — Modules pluggables vía compose + PipelineRequest
El shell ya no carga el flag `show_transits: bool` ni hardcodea qué
pipeline corre. La engine expone una sola API `compose(chart, offset,
&[PipelineRequest])` que la shell alimenta a partir de un map
`module_configs: HashMap<String, serde_json::Value>`. Los toggles de
overlay (transit hoy, progression/synastry/solar_arc en fase 7) viven
como módulos propios en el panel.

- engine: PipelineRequest enum (variante Transit por ahora; comentarios
  con el roadmap de SecondaryProgression/SolarArc/Synastry). compose()
  es la nueva entrada canónica; compute / compute_at_offset /
  compute_with_transits_at_now quedan como atajos retrocompatibles que
  delegan en compose. bridge.rs refactor: extraído build_transit_overlay
  como helper que muta &mut RenderModel, listo para que más pipelines
  apilen capas encima.
- modules: nuevo módulo `transit::TransitModule` (id "transit", toggle
  "enabled" con hotkey [T], applies_to Natal). Sacado el toggle
  show_transits de NatalModule — ahora cada módulo declara lo suyo.
  Registry::with_builtins() registra ambos. Test asegura los dos
  aplican a Natal.
- panel: sin cambios — ya itera Registry::for_kind(kind) y renderea
  cada módulo aplicable con sus controls. La adición del TransitModule
  aparece automática como segunda card en el panel.
- shell: replace show_transits por module_configs map. build_requests()
  deriva PipelineRequest::Transit cuando module_configs["transit"]
  ["enabled"] == true. on_panel_event: toggles del NatalModule afectan
  solo visibility del canvas; toggles de otros módulos van al
  module_configs y disparan render_current. on_canvas_event: [T]
  hotkey → flip transit.enabled + sync panel + recompose. apps Cargo
  agrega serde_json como dep directa.

Todos los tests verdes. Fase 7 puede sumar overlays adicionales
(progression, solar_arc) solo agregando variantes a PipelineRequest +
helpers en bridge + módulos declarativos — sin tocar el shell.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-17 10:31:11 +00:00
sergio c48638fe87 feat(tahuantinsuyu): scaffolding del estudio astrológico (10 crates + ventana 3-panes)
Módulo nuevo `modules/tahuantinsuyu/` con 9 crates reusables + app
`apps/tahuantinsuyu` ejecutable que abre la ventana del explorador y
coordina los widgets:

- tahuantinsuyu-card: Card Brahman + spawn_sidecar (flows
  chart-request/chart-result).
- tahuantinsuyu-model: tipos agnósticos (Group/Contact/Chart,
  StoredBirthData, StoredChartConfig, ChartKind, TreeSelection).
- tahuantinsuyu-store: persistencia SQLite (rusqlite) con migración v1,
  CRUD por entidad y descenso recursivo `charts_under_group`.
- tahuantinsuyu-engine: bridge agnóstico al canvas vía `RenderModel`
  (Layer/Glyph/Geometry). Feature `eternal-bridge` (off por default)
  reservada para enchufar eternal-astrology desde ~/eternal.
- tahuantinsuyu-modules: registry de módulos pluggables (Module trait
  + Control schema) con `NatalModule` placeholder.
- tahuantinsuyu-theme: AstroPalette (elementos / modos / planetas /
  aspectos) con variantes dark + light sobre yahweh-theme.
- tahuantinsuyu-canvas: widget GPUI con CanvasState (Empty / Wheel /
  Thumbnails). Render placeholder hasta cablear la rueda real.
- tahuantinsuyu-tree: explorador izquierdo sobre yahweh-widget-tree,
  prefijos g:/c:/h: para Group/Contact/Chart.
- tahuantinsuyu-panel: control panel inferior que lee Controls de los
  módulos del registry y los pinta.
- apps/tahuantinsuyu: binario `tahuantinsuyu` (launch_app-style) con
  Shell coordinador (tree↔canvas↔panel), DB en $XDG_DATA_HOME.

Workspace Cargo.toml actualizado con los 10 miembros. `cargo check`
verde, tests unitarios verdes (model/store/engine/modules/theme/card).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-16 01:06:03 +00:00