[follow-up] DKIM task orphan on domain delete
closedContext
Surfaced by C2 (24dcaa6). During teardown, deleting a domain while its DKIM-management task was still in-flight left a Failed DkimManagement task in the harness with failureReason: "Failed to write DKIM signature: Invalid foreign key: Domain with id d" — an orphaned task referencing the deleted domain.
Problem
The observed lifecycle edge: a domain created with automatic DKIM schedules a DkimManagement task that materializes linked DkimSignature registry objects. Teardown must destroy those DkimSignature objects before deleting the domain (else objectIsLinked), but a domain deleted while its DKIM task is still Pending leaves a Failed task behind. The exact ordering/timing guarantee (does Stalwart cancel the task on domain delete, or is it a race?) is unverified.
Task
- Characterize the DKIM task lifecycle on domain create/delete: is the
Failedtask a benign race, or does domain deletion always need to first await/retire the pending DKIM task? - Define the correct teardown ordering contract for domains with automatic DKIM (await DKIM task → delete
DkimSignature→ delete domain) and encode it indomain.Deleteor its callers. - Confirm whether the orphaned
Failedtask self-cleans (task-retention policy) or must be explicitly removed.
Acceptance
- A documented teardown sequence that deletes a DKIM-automatic domain without leaving orphaned
DkimManagementtasks orDkimSignatureobjects. - A live test deleting a domain immediately after create (the racing case) leaves no
Failedtask, or the residual task is proven harmless and its retention documented.
Depends on: 24dcaa6 (discovering issue).
2 Comments
Expired-claim teardown makes this race steady-state
The two-gate signup flow (ADR-0005, docs/03 §4a) means domains are now created and later deleted on a schedule, not just in manual teardown. Specifically: a
verifiedclaim provisions a domain with automatic DKIM, then a claim that never reachesactive(readiness gate times out) or a hijacked zone (ownership re-proof fails on the hourly sweep) is torn down — while itsDkimManagementtask /DkimSignatureobjects may still be Pending.So the orphan-on-delete race you found is no longer an edge case; expiry GC will hit it routinely (~48 h expiry window × drift sweep). The fix therefore belongs in expiry/GC teardown ordering, not just the manual teardown path:
DkimSignatureobjects before the domain (elseobjectIsLinked).DkimManagement/DnsManagementtasks are quiescent (poll task status) before/around domain delete — or tolerate and sweep the orphanedFailedtask.Cross-references: bug
b5a31bd([C7], owns the readiness/DNS surface), ADR-0005.Resolved by ADR-0007 D19 (manual DKIM) + verified live on FDB — 2026-09-08
The orphan-on-delete race this bug described was specific to Stalwart’s automatic DKIM management: a domain created with auto-DKIM schedules a
DkimManagementtask that materializes linkedDkimSignatureobjects, and deleting the domain while that task was stillPendingleft aFailedtask.ADR-0007 D19 changed the model to manual DKIM: sovrn generates an RSA-2048 key, installs it as a
DkimSignatureobject directly (dkimManagement: Manual), and no auto-rotation task is ever scheduled. Verified live (bug70790ed, S2 probe):dkimManagement: "Manual"with zero auto-generated signatures.objectIsLinkedstill guards the delete ordering: deleting a domain with live signatures returnsobjectIsLinkedcarryinglinkedObjects=[DkimSignature…](same on FDB as SQLite).dkim.DeleteForDomain→domain.Delete(internal/dkim/dkim.go:103,internal/verifier/verifier.go:127-133); after destroy-signatures → delete-domain, zero orphanedDkimSignatureremain.The unverified “does Stalwart cancel the DKIM task on domain delete?” question is moot: the auto task no longer exists in the sovrn path. Closing recommendation below depends on owner confirmation; no code change required.