josie / alder-tools

Plot: interior-only vertical joins (endpoint '─' survived; comb fix per GLM 5.2 diagnosis) + EMA pre-smoothing before max-decimation (per DeepSeek corroboration)

a05ba41ec943c36f6079f8f77d4a2bbbf77e62ae
josie <administrator@josie-c.com> · 2026-08-30T13:52 · browse files at this commit

parents: fdbd6db

diff --git a/src/plot.rs b/src/plot.rs
index cd85f36..3207e74 100644
--- a/src/plot.rs
+++ b/src/plot.rs
@@ -115,14 +115,26 @@ pub fn render(
         return;
     }
     let shown: Vec<f64> = if samples.len() > cols {
-        let bucket = samples.len() / cols;
-        let rem = samples.len() % cols;
+        // EMA-smooth first (alpha 0.35): idle wattage jitters ±0.3 W per
+        // tick and max-decimation amplifies a single jumpy sample into a
+        // 1-row flip that defeats row hysteresis. Subagent-diagnosed.
+        let a = 0.35;
+        let mut ema = samples[0];
+        let smoothed: Vec<f64> = samples
+            .iter()
+            .map(|&v| {
+                ema = a * v + (1.0 - a) * ema;
+                ema
+            })
+            .collect();
+        let bucket = smoothed.len() / cols;
+        let rem = smoothed.len() % cols;
         let mut out = Vec::with_capacity(cols);
         let mut idx = 0;
         for c in 0..cols {
             let extra = if c < rem { 1 } else { 0 };
             let end = idx + bucket + extra;
-            out.push(samples[idx..end].iter().cloned().fold(f64::MIN, f64::max));
+            out.push(smoothed[idx..end].iter().cloned().fold(f64::MIN, f64::max));
             idx = end;
         }
         out
@@ -143,11 +155,13 @@ pub fn render(
     for (c, &l) in lvls.iter().enumerate() {
         set(l, c, '─', st);
         if c > 0 {
-            // Vertical join between the previous level and this one so a
-            // step is continuous (staircase, nvtop-style).
+            // Vertical join strictly BETWEEN the levels (endpoints excluded:
+            // both endpoint rows already carry '─' — overwriting them with
+            // '│' erased the level dash on every transition column, the
+            // "─│─│" comb). Subagent-diagnosed off-by-one.
             let prev = lvls[c - 1];
             let (top, bot) = if prev < l { (prev, l) } else { (l, prev) };
-            for r in top..=bot.min(top + rows) {
+            for r in top + 1..bot {
                 set(r, c, '│', st);
             }
         }