From cd13efdbed3e5b00b7b6634d5141668f5f32f27a Mon Sep 17 00:00:00 2001 From: Alexander Heldt Date: Tue, 22 Sep 2026 15:05:02 +0000 Subject: [PATCH] Judge the day readout by the day's kinds, not the window's MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A day whose food was all unlabelled read "Fri, Sep 18 — No kind 300 g · 300 g in total": the number twice, under a label with nothing to distinguish it from. The guard was on the wrong quantity. It asked whether the *chart* was split, when what decides this is how many kinds *that day* holds — and a chart split across other days can still land on a day of one kind. Keying off the day's own parts fixes the reported case and a second one nobody had hit yet, where a day of a single named kind read "Dry 300 g · 300 g in total". So: several kinds keep the total beside them, being what the bar's height shows and what you would otherwise add up. One kind does not, because it already is the total. And "No kind" alone drops its label, which was only ever there to tell it apart from something else. The new assertions were checked against the old guard, where five of them fail. The original ones passed throughout, which is the point — they only ever exercised a chart with one series, and this bug lives on the other axis. --- checks/food-trend.mjs | 27 +++++++++++++++++++++++++++ src/app.js | 26 ++++++++++++++++---------- 2 files changed, 43 insertions(+), 10 deletions(-) diff --git a/checks/food-trend.mjs b/checks/food-trend.mjs index 5e9ba70..d07ef20 100644 --- a/checks/food-trend.mjs +++ b/checks/food-trend.mjs @@ -315,6 +315,33 @@ suite("what the sentence is allowed to say"); "a day marked not counted says that instead of reading as empty"); } + + suite("a day holding only one kind"); + { + // The chart is split — other days have several kinds — but this day's food + // is all one. The total is that one figure, so saying it twice is noise. + kinds = [{ id: "d", name: "Dry", colorIndex: 0 }, { id: "f", name: "Fresh", colorIndex: 1 }]; + const days = [day(18, { "": 300 }), day(19, { d: 210, f: 90 }), day(20, { d: 300 })]; + + selected = "2026-09-18"; + const unlabelled = read(days).textContent; + eq(unlabelled, "Fri, Sep 18 — 300 g.", + "a day of unlabelled food gives the bare total, on a split chart too"); + ok(!/No kind/.test(unlabelled), + "…without the 'No kind' label, which has nothing to distinguish it from"); + ok(!/in total/.test(unlabelled), "…and without saying the number twice"); + + selected = "2026-09-20"; + const oneKind = read(days).textContent; + eq(oneKind, "Sun, Sep 20 — Dry 300 g.", + "a day of one named kind keeps the name, which does say something"); + ok(!/in total/.test(oneKind), "…but still does not repeat the figure"); + + selected = "2026-09-19"; + ok(/in total/.test(read(days).textContent), + "two kinds on a day still get the total beside them"); + } + suite("an unsplit chart gets the day total too"); { // No kinds defined: there is still no hover on a phone, so the figure was diff --git a/src/app.js b/src/app.js index 2a1baf6..094d4e8 100644 --- a/src/app.js +++ b/src/app.js @@ -2131,21 +2131,27 @@ } // Series order, so this reads as the stack above it read bottom to top. const parts = series - .map(s => ({ name: s.name, g: s.of(day) })) - .filter(p => p.g > 0) - .map(p => `${p.name} ${Math.round(p.g)} g`); + .map(s => ({ id: s.id, name: s.name, g: s.of(day) })) + .filter(p => p.g > 0); const total = `${Math.round(day.grams)} g`; + const label = (p) => `${p.name} ${Math.round(p.g)} g`; + // What matters is how many kinds *this day* holds, not how many the window + // does. A chart split across other days can still land on a day whose food + // is all one kind, and there the total is that kind's own figure. if (parts.length === 0) { el.textContent = `${date} — no food logged.`; - } else if (series.length <= 1) { - // Unsplit: the one part *is* the total, and naming it twice — "No kind - // 340 g · 340 g in total" — would be daft. - el.textContent = `${date} — ${total}.`; + } else if (parts.length === 1) { + // One part is the whole day, so repeating it as a total says the same + // number twice. And "No kind" as the sole label says nothing at all — + // there is nothing for it to distinguish the food from. + el.textContent = parts[0].id === NO_KIND + ? `${date} — ${total}.` + : `${date} — ${label(parts[0])}.`; } else { - // The total is worth repeating beside the parts: it is what the bar's - // height shows, and it saves adding them up. - el.textContent = `${date} — ${parts.join(" · ")} · ${total} in total.`; + // Several kinds: the total earns its place beside them, being what the + // bar's height shows and what you would otherwise add up yourself. + el.textContent = `${date} — ${parts.map(label).join(" · ")} · ${total} in total.`; } }