From df7a9159c268e44138c4641bf6b18a8f266495ab Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Thu, 6 Aug 2026 18:55:30 +0100 Subject: [PATCH] normalise image counts in compile-with-optimizable-pngs analytics events (#36308) GitOrigin-RevId: 6049161196fab1b2e4c3d9aa811b97e3e529aca2 --- .../Features/Compile/CompileController.mjs | 20 +++++-- .../src/Compile/CompileController.test.mjs | 55 ++++++++++++++++++- 2 files changed, 68 insertions(+), 7 deletions(-) diff --git a/services/web/app/src/Features/Compile/CompileController.mjs b/services/web/app/src/Features/Compile/CompileController.mjs index 80ce3e9f44..2dc538d622 100644 --- a/services/web/app/src/Features/Compile/CompileController.mjs +++ b/services/web/app/src/Features/Compile/CompileController.mjs @@ -309,27 +309,35 @@ const _CompileController = { // PNGs or contained PNGs the optimisation would have targeted. // Projects the optimisation would never have touched are excluded, // so they cannot dilute the comparison. + const latexRuns = stats?.['latex-runs'] const optimisedPngCount = stats?.['include-image-optimised'] || 0 - const optimisablePngCount = - stats?.['optimisable-png-count'] || stats?.['include-image-optimised'] + const optimisablePngCount = stats?.['optimisable-png-count'] const projectHasUnconvertedPngs = Boolean(stats?.projectHasUnconvertedPngs) - if (optimisedPngCount > 0 || projectHasUnconvertedPngs) { + if (latexRuns > 0 && (optimisedPngCount > 0 || projectHasUnconvertedPngs)) { + // included images are counted on every run, normalise them to get the number + // of images in the project - this is then comparable to optimisablePngCount which + // is computed from the project itself and does not vary with the number of runs + const normalisedOptPngCount = Math.round(optimisedPngCount / latexRuns) + const normalisedTotalImageCount = Math.round( + (stats?.['include-image-all'] || 0) / latexRuns + ) AnalyticsManager.recordEventForUserInBackground( userId, 'compile-with-optimizable-pngs', { projectId, - optimizablePngCount: optimisablePngCount, - optimizedPngCount: optimisedPngCount, + optimizablePngCount: optimisablePngCount || normalisedOptPngCount, + optimizedPngCount: normalisedOptPngCount, optimizedImageInclusionTime: timings?.['include-image-optimised'] || 0, - totalImages: stats?.['include-image-all'] || 0, + totalImages: normalisedTotalImageCount, totalImageInclusionTime: timings?.['include-image-all'] || 0, isPng2pdf: !!options.png2pdf, compiler: options.compiler, compileTime: timings?.compileE2E, isDraftMode: !!options.draft, status, + latexRuns, } ) } diff --git a/services/web/test/unit/src/Compile/CompileController.test.mjs b/services/web/test/unit/src/Compile/CompileController.test.mjs index 457aeec2f9..5bf92e2b00 100644 --- a/services/web/test/unit/src/Compile/CompileController.test.mjs +++ b/services/web/test/unit/src/Compile/CompileController.test.mjs @@ -448,6 +448,7 @@ describe('CompileController', function () { 'optimisable-png-count': 1, 'include-image-all': 3, projectHasUnconvertedPngs: 1, + 'latex-runs': 1, }, timings: { 'include-image-all': 123, compileE2E: 200 }, }) @@ -469,6 +470,7 @@ describe('CompileController', function () { compileTime: 200, isDraftMode: false, status: 'success', + latexRuns: 1, } ) }) @@ -481,6 +483,7 @@ describe('CompileController', function () { 'include-image-optimised': 2, 'include-image-all': 5, projectHasUnconvertedPngs: 0, + 'latex-runs': 1, }, timings: { 'include-image-optimised': 12, @@ -508,6 +511,48 @@ describe('CompileController', function () { compileTime: 300, isDraftMode: false, status: 'success', + latexRuns: 1, + } + ) + }) + + it('normalises the included image count for multiple runs', async function (ctx) { + ctx.CompileManager.promises.compile.resolves({ + status: 'success', + outputFiles: [], + stats: { + 'include-image-optimised': 6, + 'include-image-all': 15, + projectHasUnconvertedPngs: 0, + 'latex-runs': 3, + }, + timings: { + 'include-image-optimised': 12, + 'include-image-all': 34, + compileE2E: 300, + }, + }) + await ctx.CompileController.compile(ctx.req, ctx.res, ctx.next) + expect( + ctx.AnalyticsManager.recordEventForUserInBackground + ).to.have.been.calledWith( + ctx.user_id, + 'compile-with-optimizable-pngs', + { + projectId: ctx.projectId, + // Falls back to the optimised-image count when 'optimisable-png-count' + // is absent from stats (e.g. an older clsi that predates the field). + optimizablePngCount: 2, + optimizedPngCount: 2, + optimizedImageInclusionTime: 12, + totalImages: 5, + totalImageInclusionTime: 34, + isPng2pdf: false, + compiler: undefined, + compileTime: 300, + isDraftMode: false, + status: 'success', + latexRuns: 3, } ) }) @@ -521,6 +566,7 @@ describe('CompileController', function () { 'include-image-optimised': 2, 'include-image-all': 5, projectHasUnconvertedPngs: 1, + 'latex-runs': 1, }, timings: { 'include-image-optimised': 12, @@ -546,6 +592,7 @@ describe('CompileController', function () { compileTime: 400, isDraftMode: false, status: 'success', + latexRuns: 1, } ) }) @@ -559,6 +606,7 @@ describe('CompileController', function () { 'optimisable-png-count': 1, 'include-image-all': 3, projectHasUnconvertedPngs: 1, + 'latex-runs': 1, }, timings: { 'include-image-all': 123, compileE2E: 456 }, }) @@ -580,6 +628,7 @@ describe('CompileController', function () { compileTime: 456, isDraftMode: true, status: 'failure', + latexRuns: 1, } ) }) @@ -588,7 +637,11 @@ describe('CompileController', function () { ctx.CompileManager.promises.compile.resolves({ status: 'success', outputFiles: [], - stats: { 'include-image-all': 3, projectHasUnconvertedPngs: 0 }, + stats: { + 'include-image-all': 3, + projectHasUnconvertedPngs: 0, + 'latex-runs': 1, + }, timings: {}, }) await ctx.CompileController.compile(ctx.req, ctx.res, ctx.next)