[UPDATE] Five polish items finished back-to-back, closing out the improvement queue started on 2026-04-18.
#30 Audit-chain verification cron — bin/verify-audit-chain.php runs AuditLog::verifyChain() under CronTracker. Clean runs exit 0; a break logs CRITICAL (Sentry + forum alert) and exits non-zero so cron's own failure reporting engages. Cron line: 30 3 * * 1 php bin/verify-audit-chain.php.
#31 Log rotation on file size — Logger now rotates the current-day file to app-YYYY-MM-DD.<epoch>.log when it exceeds LOG_MAX_BYTES (default 100 MB). Daily rollover still happens at UTC midnight; 0 disables size-based rotation.
#32 Pagination clamp — new Config::paginationLimit() reads general.pagination_limit and clamps to [1, 500] with a default of 25. 13 controllers swept to use it; a corrupted config can no longer drive per-page SELECTs into the millions.
#33 Validator unique rule — added unique => [table, column, case_insensitive?, except_id?, message?] to Validator. The register flow's post-validate User::usernameExists / User::emailExists branches are gone — one rule set now covers all three failure modes. Fails closed on DB unreachable.
#34 Admin subnav dropdowns — three inline onclick="this.parentElement.classList.toggle('open')" swapped for the data-admin-subnav-toggle pattern with a delegated handler in app.js. Same shape as the earlier mobile nav-dropdown fix: stops propagation, closes siblings, only one open at a time.
That wraps the approved list (1–24 + 29–34). Items 25 / 26 / 27 (Collections, Marketplace, Pen-pal) remain as deferred future work per their own explicit call-out, and 28 ("Today in retro history") was skipped during this run.
Automated system post — 2026-04-18 11:36:24 CDT
. __ ____ ___ ____ _ _
/ /_| ___| / _ \___ \(_)___| |__
| '_ \___ \| | | |__) | / __| '_ \
| (_) |__) | |_| / __/| \__ \ | | |
\___/____/ \___/_____|_|___/_| |_|
D2sk - Sysop