feat: render pipeline optimization (Phase 0) #94
No reviewers
Labels
No Label
ai-changes-requested
ai-failed
ai-merged
ai-pr-opened
ai-reviewed
ai-reviewing
ai-reviewing
ai-working
bug
enhancement
evolution
performance
phase-0
phase-1a
phase-1b
phase-1c
phase-1d
security
tech-debt
todo
No Milestone
No project
No Assignees
2 Participants
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: cal/paper-dynasty-database#94
Loading…
Reference in New Issue
Block a user
No description provided.
Delete Branch "feature/render-pipeline-optimization"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Eliminates ~1.5s browser spawn overhead and ~0.4s font CDN round-trip
per card render. Target: per-card render from ~3s to <1s.
Refs: #88, #89, #90
Co-Authored-By: Claude Opus 4.6 noreply@anthropic.com
74294c38cetoc262bb431eAI Code Review
Files Reviewed
app/main.py(modified)app/routers_v2/players.py(modified)storage/templates/player_card.html(modified)storage/templates/style.html(modified — base64 WOFF2 font data)Findings
Correctness
get_browser()) and cleanly shuts it down on exit (shutdown_browser()). The render refactor correctly replaces the per-requestasync with async_playwright()context manager withget_browser()+page.close()in afinallyblock — browser leak on exception is prevented.get_browser()checks_browser.is_connected()before reuse, tears down the stale playwright instance, then re-launches. Correct for crash recovery.new_page(viewport={"width": 1280, "height": 720})was added; screenshot clips to{"x": 0, "y": 0, "width": 1200, "height": 600}which is within bounds — no visual regression expected.player_card.htmldrops the CDN<link>tags;style.htmlnow provides the same fonts via@font-face+ base64 WOFF2, eliminating the ~0.4s CDN round-trip.f"0.1.1",f"There are no players to filter") removed.filename→_filenamesuppresses the unused-variable warning.Edge Cases
get_browser()under concurrent reconnect. The singleton guardif _browser is None or not _browser.is_connected()is not protected by an asyncio lock. If two requests hit this check simultaneously while_browseris None or disconnected (e.g., after a crash), both coroutines can enter the reconnect branch and the first playwright instance is leaked. In practice, risk is low: the lifespan hook pre-warms before any request is served, and browser crashes are rare in a containerized env. Flagged as a suggestion only.Security
[REDACTED]log pattern regressions — verified all logging calls in the diff.--no-sandbox+--disable-dev-shm-usageare standard Chromium flags for containerized environments — no security concern.Style & Conventions
get_browser/shutdown_browserfrom a router module intomain.pyis slightly unconventional, but pragmatic given the browser state must live alongside the render code. Consistent with the codebase's existing patterns._filename(line ~728 post-patch) is still dead code — suppressed rather than deleted. Minor; within the PR's stated scope of "pre-existing lint fixes".Suggestions
app/browser.pymodule somain.pydoesn't import implementation details from a router.asyncio.Lockaround the reconnect block inget_browser()to prevent playwright instance leaks:Verdict: APPROVED
Clean, well-scoped implementation. The persistent browser singleton and lifespan hooks are correct and properly integrated. Font self-hosting is a straightforward CDN removal with correct
@font-facerules. The theoretical race condition inget_browser()is low-risk given startup pre-warming and is flagged as a suggestion only.Automated review by Claude PR Reviewer
New commits pushed, approval review dismissed automatically according to repository settings