Both found while investigating the Winchester Walking Weekend performance problem.
Walks shown as fully booked when capacity is unknown: When maxCapacity resolves to 0 (loadBookingConfig returns null on the server, or the bookingConfig() signal has not loaded yet on the client) the check totalBooked >= maxCapacity was always true, rendering every walk as "Fully booked - all 0 places taken". Guard both the server eligibility endpoint and the client refreshCapacity fallback with maxCapacity > 0 && ... so a 0/unknown capacity is treated as no limit. Genuinely-full walks are unaffected.
Batch-send progress map leaked: startBatchTransactionalSend stored a BatchSendProgress in a module-level jobs Map for every composer batch send and never removed it, so each send's per-recipient progress stayed in memory for the life of the process and pushed heapUsed toward the V8 heap limit (~259 MB on a 512 MB machine), causing major-GC slowness. pruneCompletedJobs() now drops terminal jobs older than 30 minutes and caps the map at 100 (oldest terminal first); running jobs are never evicted and the window leaves time for the client to poll final status.
Scheduled-run RSS logging: executeTask records process RSS before and after each scheduled run into scheduledTaskRuns.message (via the shared humanFileSize helper), to attribute any remaining per-job memory growth.