mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-10-22 03:49:18 +02:00
fix(stats): cancelled prints get their own bucket; gauge denominator excludes them (#1390 follow-up)
Reporter (@IndividualGhost1905) saw Total: 20 / Success: 18 / Failed: 1 and asked where the 20th print went. The Quick Stats endpoint counted status == "completed" → Successful and status == "failed" → Failed, but used a raw count(*) for Total Prints, so the four other PrintLogEntry statuses (aborted, stopped, cancelled, skipped) silently inflated the total without showing up in any breakdown row. The earlier #1390 round had committed a test locking in this exact behaviour ("uses total_prints as denominator so cancelled/stopped events count"), which was wrong: it conflated user intent with print quality. Three-bucket classification, applied across the whole stats surface and matching how the rest of the codebase already groups statuses (main.py:430, 1729; failure_analysis status filter): successful = completed failed = failed + aborted (printer-detected quality failures) cancelled = stopped + cancelled + skipped (user/queue stopped) Quick Stats endpoint returns the new cancelled_prints field; ArchiveStats.cancelled_prints defaults to 0 so older fixtures still parse. SuccessRateWidget gauge now divides by successful + failed only — a cancelled roll no longer drags the gauge down — and a Cancelled row appears in the breakdown so the missing prints don't silently vanish from Total Prints. Failure Analysis service applies the same denominator fix to both the headline failure_rate and the per-week trend, so a week with several cancellations and zero failures reads as 0% rather than a misleading "failed / total". i18n: new stats.cancelled key in all 9 locales with real translations (no English fallback), parity script clean. Tests: the existing 'uses total_prints as denominator' assertion is inverted to assert the new behaviour (40 / 20 / 35 → 67% gauge, Cancelled: 35 visible). The unchanged-display path (140 / 10 / 0 → 93%) still holds since 140 / (140 + 10) = 93.33% rounds the same. 33 StatsPage tests + 6 backend stats/failure tests green.
This commit is contained in:
@@ -14,6 +14,7 @@ const mockStats = {
|
||||
total_prints: 150,
|
||||
successful_prints: 140,
|
||||
failed_prints: 10,
|
||||
cancelled_prints: 0,
|
||||
total_print_time_hours: 500.5,
|
||||
total_filament_grams: 5500,
|
||||
total_cost: 125.50,
|
||||
@@ -215,11 +216,14 @@ describe('StatsPage', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('uses total_prints as denominator so cancelled/stopped events count (#1390)', async () => {
|
||||
// 40 successful out of 100 total — with 20 failed and 40 cancelled/stopped
|
||||
// mixed in. Old formula (successful / (successful + failed)) would have
|
||||
// shown 40 / (40 + 20) = 67%. New formula shows 40 / 100 = 40%, which
|
||||
// matches the "Total Prints: 100" the user reads right above the gauge.
|
||||
it('excludes cancelled prints from the rate denominator and surfaces them in the breakdown (#1390)', async () => {
|
||||
// 40 completed, 20 failed (printer-detected), 40 user-cancelled out of
|
||||
// 100 total. The earlier fix divided by total_prints and reported 40%,
|
||||
// which conflated user intent with print quality — cancelling a roll
|
||||
// because you changed your mind shouldn't be counted against the
|
||||
// printer's success rate. New behaviour: gauge = 40 / (40 + 20) = 67%;
|
||||
// cancelled count still visible in the row breakdown so the missing
|
||||
// 40 prints don't silently disappear.
|
||||
server.use(
|
||||
http.get('/api/v1/archives/stats', () =>
|
||||
HttpResponse.json({
|
||||
@@ -227,6 +231,7 @@ describe('StatsPage', () => {
|
||||
total_prints: 100,
|
||||
successful_prints: 40,
|
||||
failed_prints: 20,
|
||||
cancelled_prints: 35,
|
||||
}),
|
||||
),
|
||||
);
|
||||
@@ -234,7 +239,13 @@ describe('StatsPage', () => {
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Success Rate')).toBeInTheDocument();
|
||||
expect(screen.getByText('40%')).toBeInTheDocument();
|
||||
expect(screen.getByText('67%')).toBeInTheDocument();
|
||||
// Cancelled count surfaces in the breakdown so the missing prints
|
||||
// aren't silently swallowed (was the original bug in #1390). Pick a
|
||||
// value distinct from successful_prints/failed_prints to keep the
|
||||
// getByText query unambiguous.
|
||||
expect(screen.getByText('Cancelled:')).toBeInTheDocument();
|
||||
expect(screen.getByText('35')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user