Give the food trend's figures, not only its rate
"Up about 40 g a week" is a rate with nothing to anchor it: it says the line slopes without saying where it sits. The sentence now names both ends of the fit — "roughly 280 g a day then, 400 g a day now" — which is the reading anyone actually wants from a growth chart. When the fit is not trustworthy it quotes the average instead, and says the day-to-day variation is larger than any trend. That difference is the point. The average is a measurement and survives the noise; the ends of the line are the line's own output, and quoting them on a fit nobody should read would dress a guess up as a reading. Everything rounds to 10 g for the same reason — "287 g a day" would be false precision from four noisy points. The wording moves into a pure foodTrendSentence() so those rules can be checked, which is worth doing precisely because they are judgement rather than arithmetic: the checks now pin that a clear climb gives both figures, a flat run gives the average and no endpoints, a see-saw gives neither, and nothing is ever quoted to the gram.
This commit is contained in:
@@ -5,6 +5,7 @@ import { load } from "./extract.mjs";
|
||||
import { suite, eq, ok, report } from "./assert.mjs";
|
||||
|
||||
const app = load({ names: ["foodTrend"] });
|
||||
const words = load({ names: ["foodTrendSentence"] });
|
||||
|
||||
// The 7/14/30 picker reaches the trend by deciding how many days weeklyData
|
||||
// builds — there is no second mechanism, so this is the thing to hold still.
|
||||
@@ -86,4 +87,35 @@ suite("marked days are skipped without shifting the line");
|
||||
ok(t.clear, "…and it is still clear, not drowned by a false zero");
|
||||
}
|
||||
|
||||
suite("what the sentence is allowed to say");
|
||||
{
|
||||
const say = (grams, opts) => words.foodTrendSentence(app.foodTrend(days(grams, opts)), 14);
|
||||
|
||||
const rising = say([200, 250, 300, 350, 400, 450, 0]);
|
||||
ok(/up about 350 g a week/.test(rising), "a clear climb gives the rate");
|
||||
ok(/200 g a day then/.test(rising) && /450 g a day now/.test(rising),
|
||||
"…and the figures at each end of the line, so it is not only a rate");
|
||||
ok(/the last 14 days/.test(rising), "…named against the window it was fitted over");
|
||||
|
||||
const steady = say([300, 302, 298, 301, 299, 300, 0]);
|
||||
ok(/roughly steady/.test(steady), "a flat run is called steady");
|
||||
ok(/averaging about 300 g a day/.test(steady),
|
||||
"…and quotes the average, which is a measurement rather than model output");
|
||||
ok(!/then/.test(steady) && !/ now\b/.test(steady),
|
||||
"…but not fitted endpoints, which would dress up a line nobody should read");
|
||||
|
||||
const noisy = say([200, 500, 210, 480, 190, 520, 0]);
|
||||
ok(/roughly steady/.test(noisy) && /variation is larger/.test(noisy),
|
||||
"a see-saw says the variation beat the trend, rather than quoting a slope");
|
||||
|
||||
const none = say([300, 320, 310]);
|
||||
ok(/Not enough complete days/.test(none) && /needs four/.test(none),
|
||||
"too few days explains itself instead of leaving the chart bare");
|
||||
|
||||
// False precision would make a fit look like a reading.
|
||||
ok(/\b\d*[05] g a day/.test(rising), "figures are rounded to 10 g, not quoted to the gram");
|
||||
const falling = say([450, 400, 350, 300, 250, 200, 0]);
|
||||
ok(/down about/.test(falling), "a clear fall says down");
|
||||
}
|
||||
|
||||
export default report("food-trend");
|
||||
|
||||
Reference in New Issue
Block a user