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>
This commit is contained in:
@@ -123,6 +123,7 @@ impl Registry {
|
||||
pub fn with_builtins() -> Self {
|
||||
let mut r = Self { modules: Vec::new() };
|
||||
r.register(Box::new(natal::NatalModule));
|
||||
r.register(Box::new(transit::TransitModule));
|
||||
r
|
||||
}
|
||||
|
||||
@@ -203,12 +204,6 @@ pub mod natal {
|
||||
default: true,
|
||||
hotkey: Some("P".into()),
|
||||
},
|
||||
Control::Toggle {
|
||||
key: "show_transits".into(),
|
||||
label: "Tránsitos (ahora)".into(),
|
||||
default: false,
|
||||
hotkey: Some("T".into()),
|
||||
},
|
||||
Control::Slider {
|
||||
key: "harmonic".into(),
|
||||
label: "Armónico".into(),
|
||||
@@ -229,15 +224,68 @@ pub mod natal {
|
||||
}
|
||||
}
|
||||
|
||||
// =====================================================================
|
||||
// TransitModule — overlay del cielo del momento sobre la carta natal
|
||||
// =====================================================================
|
||||
|
||||
pub mod transit {
|
||||
use super::*;
|
||||
|
||||
/// Anillo externo con las posiciones planetarias del **instante
|
||||
/// actual** (reloj de pared) sobre el sujeto natal, más las
|
||||
/// cross-aspects natal × transit. La engine despacha al pipeline
|
||||
/// `PipelineRequest::Transit` cuando este módulo está activo en el
|
||||
/// `module_configs` del shell.
|
||||
pub struct TransitModule;
|
||||
|
||||
impl Module for TransitModule {
|
||||
fn id(&self) -> &'static str {
|
||||
"transit"
|
||||
}
|
||||
fn label(&self) -> &'static str {
|
||||
"Tránsitos"
|
||||
}
|
||||
fn description(&self) -> &'static str {
|
||||
"Cielo del momento sobre la natal + cross aspects."
|
||||
}
|
||||
fn applies_to(&self, kind: ChartKind) -> bool {
|
||||
// Por ahora solo overlay sobre cartas natales — más adelante
|
||||
// podríamos overlayar tránsitos sobre Progresiones, etc.
|
||||
matches!(kind, ChartKind::Natal)
|
||||
}
|
||||
fn enabled_by_default(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn controls(&self) -> Vec<Control> {
|
||||
vec![Control::Toggle {
|
||||
key: "enabled".into(),
|
||||
label: "Activar".into(),
|
||||
default: false,
|
||||
hotkey: Some("T".into()),
|
||||
}]
|
||||
}
|
||||
fn compute_layers(&self, _chart: &Chart, _cfg: &serde_json::Value) -> Vec<Layer> {
|
||||
// Las capas de tránsito se construyen en la engine vía
|
||||
// `PipelineRequest::Transit` porque necesitan acceso a la
|
||||
// NatalChart cruda + EphemerisSession. Este método queda
|
||||
// como no-op — el módulo es puramente declarativo.
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn registry_finds_natal() {
|
||||
fn registry_finds_builtins() {
|
||||
let r = Registry::with_builtins();
|
||||
assert!(r.find("natal").is_some());
|
||||
assert_eq!(r.for_kind(ChartKind::Natal).len(), 1);
|
||||
assert!(r.find("transit").is_some());
|
||||
// Natal kind tiene 2 módulos aplicables: el propio + transit overlay.
|
||||
assert_eq!(r.for_kind(ChartKind::Natal).len(), 2);
|
||||
// Synastry kind no tiene módulos hoy.
|
||||
assert!(r.for_kind(ChartKind::Synastry).is_empty());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user