Found during the /plan-eng-review of #45.
normalize._image_to_pdf (backend/processing/normalize.py:104-105) and _html_to_pdf (:114-115) write storage/converted/<stem>_converted.pdf. pipeline.py:53 then save_converteds that to storage/converted/<hash>.pdf and walks away. Nothing deletes the scratch file.
Only gmail.py:180 and :199 clean up, and only on their success paths.
Measured live: 66 files in converted/ — 33 real <hash>.pdf and 33 <hash>_converted.pdf, 5.7MB of pure duplicate, i.e. converted/ is roughly twice the size it needs to be.
Two structural notes worth recording:
save_converted has an exists-guard (backend/storage.py:33) while _image_to_pdf rewrites the scratch on every reprocess. So <hash>.pdf is the oldest conversion and <hash>_converted.pdf is the newest — the intuition is backwards. Measured: 31 of 33 pairs byte-identical, 2 differ (same size, different bytes — PDF /CreationDate). Change page_render_dpi once and <hash>.pdf is a conversion at a DPI nothing else in the system uses.
gmail.py:175 calls normalize_file on a system tempfile, so a failure between the write and the unlink leaks converted/tmpXXXXXXXX_converted.pdf — a name nothing will ever match.
#45 excludes the paired scratch from backups (when the partner exists and is the same size). It deliberately does not delete anything from the live tree — that is this issue.
Related: #45, #46, #51.
Found during the /plan-eng-review of #45.
normalize._image_to_pdf(backend/processing/normalize.py:104-105) and_html_to_pdf(:114-115) writestorage/converted/<stem>_converted.pdf.pipeline.py:53thensave_converteds that tostorage/converted/<hash>.pdfand walks away. Nothing deletes the scratch file.Only
gmail.py:180and:199clean up, and only on their success paths.Measured live: 66 files in
converted/— 33 real<hash>.pdfand 33<hash>_converted.pdf, 5.7MB of pure duplicate, i.e.converted/is roughly twice the size it needs to be.Two structural notes worth recording:
save_convertedhas an exists-guard (backend/storage.py:33) while_image_to_pdfrewrites the scratch on every reprocess. So<hash>.pdfis the oldest conversion and<hash>_converted.pdfis the newest — the intuition is backwards. Measured: 31 of 33 pairs byte-identical, 2 differ (same size, different bytes — PDF/CreationDate). Changepage_render_dpionce and<hash>.pdfis a conversion at a DPI nothing else in the system uses.gmail.py:175callsnormalize_fileon a system tempfile, so a failure between the write and the unlink leaksconverted/tmpXXXXXXXX_converted.pdf— a name nothing will ever match.#45 excludes the paired scratch from backups (when the partner exists and is the same size). It deliberately does not delete anything from the live tree — that is this issue.
Related: #45, #46, #51.