feat(cosmobiologia): rectificador per-segundo + direcciones primarias reales

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>
This commit is contained in:
sergio
2026-05-22 16:56:06 +00:00
parent 5fdae159f0
commit 36d6645e7f
6 changed files with 165 additions and 167 deletions
+10 -4
View File
@@ -1410,12 +1410,18 @@ impl Shell {
.unwrap_or("naibod")
.to_string();
// Ventana ±15 min, paso 1 min — el barrido GR estándar.
match cosmobiologia_engine::rectificar(&chart, &eventos, 15, 1, &key_gr) {
// Ventana ±15 min — dos pasadas (minuto grueso, segundo fino).
match cosmobiologia_engine::rectificar(&chart, &eventos, 15, &key_gr) {
Ok(r) => {
// Offset en segundos → texto «±Xm Ys».
let seg = r.mejor_offset_segundos;
let signo = if seg < 0 { "-" } else { "+" };
let abs = seg.abs();
let resumen = format!(
"{:+} min · puntaje {:.2}",
r.mejor_offset_minutos, r.mejor_puntaje
"{signo}{}m {:02}s · error {:.2}a",
abs / 60,
abs % 60,
r.mejor_puntaje
);
self.panel.update(cx, |p, cx| {
p.set_string("primary_directions", "resultado", Some(resumen), cx)