Never chase a member who already signed, and keep the subject plain

FixDocsService
Shipped
August 7, 2026 at 12:57 AM UTC
Author
Kamo
Commit
daa0d52

Two behavioural defects in the phase-8 notification path. 1. The reminder sweep ran over OPEN_STATES, which includes AWAITING_OTHERS — "this member finished; other signers have not". The member owes nothing, but Finish never clears dueAt, so the row keeps matching the sweep's predicate forever. A member who signed ON TIME received the completion receipt ("is complete. Thank you.") and then "Finish your package — 7 days overdue", then 14, then 21, every seven days until the counterparty signed, because past-due-max-periods:0 means UNLIMITED. Nothing they could do would stop it: the wizard has nothing left to show them. The sweep now reads REMINDABLE_STATES — PENDING and IN_PROGRESS. OPEN_STATES stays correct everywhere else it is used (badge count, delivery, void, redelivery): those ask "is this row still live work", a reminder asks "does THIS MEMBER still owe an action". Filtered in the predicate, so an unchaseable row is never read. 2. packageTitle was HTML-escaped unconditionally, and EmailTemplateService renders the subject and the body from the same map, so "Employee's Handbook" shipped as "Employee's Handbook" in a Subject header. The recorder now also supplies packageTitlePlain for the four canonical subjects: unescaped, and CR/LF-stripped, since a subject is the one place a title reaches a header and a newline there is header injection. Also documents that LegalMemberLink deliberately falls back to an active unverified domain rather than skipping — the javadoc argued the opposite of what the code does. DocsService 379/0 (was 374): +5 regression tests.

All changes

Like what you see shipping?

Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.

Start Free ForeverView Pricing