From 8c1f5b8f60d3643a1144646300439c5099be58d5 Mon Sep 17 00:00:00 2001 From: Paul Trowbridge Date: Thu, 17 Sep 2026 13:36:55 -0400 Subject: [PATCH] Use an ASCII separator: ExprTK string literals are byte-wise isprint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "01 · Prior Year" would not parse -- Invalid `expressions` "Bucket": Invalid string token: 01. ExprTK's string scanner validates each *byte*: is_valid_string_char(c) = isprint((unsigned char) c) || is_whitespace(c) "·" is U+00B7, two bytes 0xC2 0xB7 in UTF-8, and isprint(0xC2) is false in the C locale. The literal fails at that byte and the parser reports from the start of it, which is why the message names "01" rather than the character it actually objected to. " - " instead, which matches the "07 - Dec" already in the source data rather than introducing a second convention. The same rule applies to the label being compared, so a bucket or segment named with anything outside printable ASCII is left unordered rather than emitted into an expression that will not parse -- an unparseable expression loses the whole column, not just that one case. Co-Authored-By: Claude Opus 5 (1M context) --- ui/src/views/Baseline.jsx | 2 +- ui/src/views/Forecast.jsx | 23 +++++++++++++++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/ui/src/views/Baseline.jsx b/ui/src/views/Baseline.jsx index 0c151fc..270c71d 100644 --- a/ui/src/views/Baseline.jsx +++ b/ui/src/views/Baseline.jsx @@ -426,7 +426,7 @@ export default function Baseline({ sources = [], sourceId, versions = [], versio - {String(i + 1).padStart(2, '0')} + {String(i + 1).padStart(2, '0')} - {b}