Two bugs in the same tick path.
1. installed_on / trained_on were written only as a side effect of a status
UPGRADE. The ~300 APEX-imported projects are already at 'live' -- the furthest
status -- so ticking Installation or Training upgraded nothing and therefore
recorded nothing, and the UI's own date writers were removed in the Client
Detail redesign, leaving those columns unfillable and the Module Directory's
"Installed" column blank forever. The date is now stamped whenever the step is
ticked, independent of any status move: same transaction, same audit payload,
still write-once (an existing date is never overwritten) and still no downgrade.
A tick that changes neither status nor a date now writes nothing at all.
2. setMilestone wrote payment_id/document_id as `done ? linked : null`, so any tick
that did not resend the ids cleared them. bulkSetMilestone routes through it and
never passes ids (one key, many projects), so a single bulk re-tick silently cut
every project's step loose from the payment or quotation it had been linked to.
An already-done step now keeps the link it carries when nothing is supplied.
An explicit empty id is still an unlink, and unticking still clears both.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>