Skip to content

Cleanup findings from #100 review (reuse, simplification, efficiency)#103

Merged
IRus merged 6 commits into
mainfrom
cleanup/pr100-review-findings
Jul 7, 2026
Merged

Cleanup findings from #100 review (reuse, simplification, efficiency)#103
IRus merged 6 commits into
mainfrom
cleanup/pr100-review-findings

Conversation

@IRus

@IRus IRus commented Jul 7, 2026

Copy link
Copy Markdown
Member

Summary

Addresses the five cleanup findings from the #100 review that were deferred from the bug-fix PR (#101, now merged). Branch is off fresh main, so it builds on those fixes. Each change was delegated to codex and reviewed; behavior-preserving refactors are guarded by the existing suite (with characterization tests added where coverage was thin), and behavioral changes have their own tests. Full ./gradlew :test passes.

Changes (one commit each)

  1. Drop duplicated maxSequentialBookErrors — the abort threshold (100) was serialized into every job-status snapshot while the admin UI also hardcoded its own || 100. Removed the serialized field; the "Error Streak" metric now shows a plain count. The constant stays where it is used (the parser abort).

  2. Build the embedding translator delegate lazilyAutoTokenTypeTextEmbeddingTranslator eagerly built both the with/without-token-type variants but uses only one, fixed once the model is inspected. Now memoizes the single needed delegate on first prepare() with volatile double-checked locking. (Kept the shared-instance semantics because per-thread predictors share this one translator — a naive per-prepare() rebuild would have been a concurrency hazard.)

  3. Stream the base64 attachmentbuildRawEmail held the attachment ~4-5× in memory (raw bytes + base64 String + StringBuilder + final toByteArray). It now writes straight to a ByteArrayOutputStream via Base64.getMimeEncoder().wrap(...). Output bytes are unchanged; a new round-trip test guards the base64 body.

  4. Share one Ktor-based Content-Disposition helper — the email path hand-rolled rfc2231FileName and its own filename/filename* branching, duplicating what Ktor's ContentDisposition (already used by the download route) does. Added attachmentContentDisposition(fileName, includeAsciiFallback) in util, used by both the download route (fallback + filename*) and buildRawEmail (extended-only for Kindle), and deleted rfc2231FileName.

    • Note — intended wire-format change: the Kindle email Content-Disposition now renders in Ktor's RFC-compliant form: lowercase filename*=utf-8''… (was UTF-8'') and unquoted token filenames (filename=Clean_Title.epub instead of quoted). The percent-encoded bytes and the extended-only-for-non-ASCII behavior that Fix mojibake Kindle titles and other book-delivery improvements #100 validated for Kindle are unchanged; only the RFC-5987 charset case and token quoting differ (both standards-compliant). Two email test assertions were updated to match.
  5. Consolidate filename handling (finding gradle(deps): bump org.gradle.toolchains.foojay-resolver-convention from 0.10.0 to 1.0.0 #6, two commits):

    • Reuse the materialized filename for the Kindle attachment — the Kindle path re-derived the attachment filename from the raw book title, so it diverged from the HTTP-download filename (MaterializedBook.fileName) and blank titles lost the book_<id> uniqueness. sendBookToKindle now takes the canonical attachmentFileName; the worker passes materialized.fileName. The Subject still uses the human-readable title.
    • Extract shared sanitization primitivestakeCodePointSafe, WHITESPACE_RUN, and UNDERSCORE_RUN moved into util/TextSanitization.kt and reused by BookFileService.sanitizedTitle, EmailService.sanitizeBookTitle, and asciiFallbackFileName (previously each had its own copy). No output changes for any input.

Tests

🤖 Generated with Claude Code

IRus and others added 6 commits July 7, 2026 12:32
The abort threshold (MAX_SEQUENTIAL_BOOK_ERRORS = 100) was serialized into
every job-status snapshot while the admin UI also hardcoded its own || 100
fallback. Remove the serialized field and render the error streak as a
plain count; the constant stays where it is used (the parser abort).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
AutoTokenTypeTextEmbeddingTranslator eagerly built both the with- and
without-token-type variants but uses only one, fixed once the model is
inspected. Memoize the single needed delegate on first prepare() with
volatile double-checked locking; the shared instance is preserved so the
per-thread predictors that share this translator stay safe.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
buildRawEmail built the whole message in a StringBuilder, encoded the
attachment to a full-size base64 String, then copied the lot again via
toString().toByteArray() — roughly 4-5x the file size in memory per send.
Write directly to a ByteArrayOutputStream and stream the attachment
through Base64.getMimeEncoder().wrap(). Output bytes are unchanged; a new
round-trip test guards the base64 body.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The email path hand-rolled rfc2231FileName and its own filename/filename*
branching, duplicating what Ktor's ContentDisposition (already used by the
download route) does. Add attachmentContentDisposition(fileName,
includeAsciiFallback) in util and use it from both the download route
(fallback + filename*) and buildRawEmail (extended-only for Kindle), and
delete rfc2231FileName. The email disposition now renders in Ktor's
RFC-compliant form (lowercase utf-8'', unquoted token filenames); the
percent-encoded bytes and the extended-only-for-non-ASCII behavior are
unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Kindle path re-derived the attachment filename from the raw book
title (sanitizeBookTitle + format) instead of reusing the canonical
MaterializedBook.fileName that BookFileService already computed for HTTP
download, so the two channels delivered divergent filenames and blank
titles lost the book_<id> uniqueness. Pass the materialized filename
through sendBookToKindle as the attachment name; the Subject still uses
the human-readable title.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The code-point-safe truncation and the whitespace/underscore-collapse
regexes were duplicated across BookFileService.sanitizedTitle,
EmailService.sanitizeBookTitle, and util.asciiFallbackFileName. Extract
takeCodePointSafe, WHITESPACE_RUN, and UNDERSCORE_RUN into
util/TextSanitization.kt and reuse them. No output changes for any input.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@IRus IRus merged commit 9c450a2 into main Jul 7, 2026
7 checks passed
@IRus IRus deleted the cleanup/pr100-review-findings branch July 7, 2026 10:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant