Subject: [PATCH 14/24] wip: require explicit tiled teardown proof

From: Justin Youens <[email-masked]>
Date: Sat, 15 Aug 2026 10:43:07 -0500

---
 src/backend/Backend.cpp                 | 30 +++++++++
 src/backend/drm/DRM.cpp                 | 27 ++++++--
 src/backend/drm/TiledDRMIntegration.cpp | 83 +++++++++++++++++++++----
 src/backend/drm/TiledDRMIntegration.hpp | 23 +++++--
 tests/TiledDRMIntegration.cpp           | 44 ++++++++++++-
 5 files changed, 186 insertions(+), 21 deletions(-)

diff --git a/src/backend/Backend.cpp b/src/backend/Backend.cpp
index ceee7131334aa34ae04de427602f5295f773f2fc..a82b4e0da03ac086103c616219629c9d52b6f7c4 100644
--- a/src/backend/Backend.cpp
+++ b/src/backend/Backend.cpp
@@ -47,6 +47,16 @@ static const char* backendTypeToName(eBackendType type) {
     return "invalid";
 }
 
+static bool tiledDetachBegan(NDRM::NTiledDRMIntegration::eDetachResult result) {
+    using NDRM::NTiledDRMIntegration::eDetachResult;
+    return result == eDetachResult::BEGUN || result == eDetachResult::ALREADY_BEGUN;
+}
+
+static bool tiledDetachTerminalized(NDRM::NTiledDRMIntegration::eDetachResult result) {
+    using NDRM::NTiledDRMIntegration::eDetachResult;
+    return result == eDetachResult::TERMINALIZED || result == eDetachResult::ALREADY_TERMINALIZED;
+}
+
 Aquamarine::CBackend::CBackend() {
     ;
 }
@@ -130,11 +140,21 @@ Aquamarine::CBackend::~CBackend() {
         DRM->listeners.sessionActivate.reset();
         DRM->listeners.gpuChange.reset();
         DRM->listeners.gpuRemove.reset();
+
+        // Published DRM poll callbacks retain this CBackend. Entering its
+        // destructor therefore proves callback ingress has already gone.
+        if (tiledDetachBegan(DETACH) &&
+            !tiledDetachTerminalized(
+                NDRM::NTiledDRMIntegration::terminalizeDetached(DRM, NDRM::NTiledDRMIntegration::eDetachTerminalProof::BACKEND_OBJECT_DESTRUCTING_NO_CALLBACKS)))
+            std::terminate();
+
         for (auto& connector : DRM->connectors) {
             connector->disconnect();
             connector.reset();
         }
         DRM->connectors.clear();
+        // Keep the terminalized sidecar tombstone until CDRMBackend itself is
+        // destroyed; external implementation owners may still exist.
     }
     implementations.clear();
 }
@@ -165,11 +185,21 @@ bool Aquamarine::CBackend::start() {
         DRM->listeners.sessionActivate.reset();
         DRM->listeners.gpuChange.reset();
         DRM->listeners.gpuRemove.reset();
+
+        // This helper is called only while start() is synchronously failing.
+        // No getPollFDs() result has escaped to a caller; the local probe used
+        // to classify an implementation is destroyed before this call.
+        if (tiledDetachBegan(DETACH) &&
+            !tiledDetachTerminalized(NDRM::NTiledDRMIntegration::terminalizeDetached(DRM, NDRM::NTiledDRMIntegration::eDetachTerminalProof::CALLBACK_INGRESS_NEVER_PUBLISHED)))
+            std::terminate();
+
         for (auto& connector : DRM->connectors) {
             connector->disconnect();
             connector.reset();
         }
         DRM->connectors.clear();
+        // The implementation drop below eventually enters CDRMBackend's
+        // destructor, which alone erases the terminalized tombstone.
     };
     const auto PREPARE_ALL_DRM_DROPS = [&] {
         for (const auto& implementation : implementations)
diff --git a/src/backend/drm/DRM.cpp b/src/backend/drm/DRM.cpp
index 67fad21ba461a31f7a9dcbcd434ff33345980292..e9afd9bb18cd2f05d7b8c115ff9278947af2ab0a 100644
--- a/src/backend/drm/DRM.cpp
+++ b/src/backend/drm/DRM.cpp
@@ -56,6 +56,7 @@ using namespace Hyprutils::Math;
 namespace {
     using Aquamarine::NDRM::NTiledDRMIntegration::eDetachReason;
     using Aquamarine::NDRM::NTiledDRMIntegration::eDetachResult;
+    using Aquamarine::NDRM::NTiledDRMIntegration::eDetachTerminalProof;
     using Aquamarine::NDRM::NTiledDRMIntegration::SAllocationCapture;
     using Aquamarine::NDRM::NTiledDRMIntegration::eAllocationCaptureResult;
     using Aquamarine::NDRM::NTiledDRMIntegration::eScanCommitResult;
@@ -371,6 +372,10 @@ namespace {
         return result == eDetachResult::BEGUN || result == eDetachResult::ALREADY_BEGUN;
     }
 
+    bool detachTerminalized(eDetachResult result) {
+        return result == eDetachResult::TERMINALIZED || result == eDetachResult::ALREADY_TERMINALIZED;
+    }
+
     bool validSessionResult(Aquamarine::NDRM::NTiledDRMIntegration::eSessionResult result) {
         using Aquamarine::NDRM::NTiledDRMIntegration::eSessionResult;
         return result == eSessionResult::ROTATED || result == eSessionResult::NOT_ATTACHED;
@@ -721,13 +726,18 @@ Aquamarine::CDRMBackend::~CDRMBackend() {
     listeners.gpuChange.reset();
     listeners.gpuRemove.reset();
 
+    // A published DRM poll source retains SELF, so reaching this destructor
+    // proves that no callback ingress can still target this backend object.
+    if (detachBegan(DETACH) && !detachTerminalized(NDRM::NTiledDRMIntegration::terminalizeDetached(self, eDetachTerminalProof::BACKEND_OBJECT_DESTRUCTING_NO_CALLBACKS)))
+        std::terminate();
+
     for (auto& conn : connectors) {
         conn->disconnect();
         conn.reset();
     }
     connectors.clear();
 
-    if (detachBegan(DETACH) && NDRM::NTiledDRMIntegration::eraseDetached(self) != eDetachResult::DETACHED)
+    if (detachBegan(DETACH) && NDRM::NTiledDRMIntegration::eraseTerminalized(self) != eDetachResult::DETACHED)
         std::terminate();
 
     if (rendererState.allocator)
@@ -1297,14 +1307,23 @@ bool Aquamarine::CDRMBackend::registerGPU(SP<CSessionDevice> gpu_, SP<CDRMBacken
         SELF->listeners.sessionActivate.reset();
         SELF->listeners.gpuChange.reset();
         SELF->listeners.gpuRemove.reset();
+
+        // Withdraw the backend's published poll source before destroying
+        // grouped authority. SELF keeps the implementation alive until this
+        // callback completes; DRM_DEVICE_GONE is the terminal callback proof.
+        std::erase_if(PARENT->implementations, [&SELF](const auto& implementation) { return dynamicPointerCast<CDRMBackend>(implementation) == SELF; });
+        PARENT->events.pollFDsChanged.emit();
+
+        if (detachBegan(DETACH) && !detachTerminalized(NDRM::NTiledDRMIntegration::terminalizeDetached(SELF, eDetachTerminalProof::DRM_DEVICE_GONE)))
+            std::terminate();
+
         for (auto& connector : SELF->connectors) {
             connector->disconnect();
             connector.reset();
         }
         SELF->connectors.clear();
-
-        std::erase_if(PARENT->implementations, [&SELF](const auto& implementation) { return dynamicPointerCast<CDRMBackend>(implementation) == SELF; });
-        PARENT->events.pollFDsChanged.emit();
+        // Poll-source owners may retain SELF after GPU removal. Its eventual
+        // destructor alone erases the terminalized sidecar tombstone.
     });
 
     return true;
diff --git a/src/backend/drm/TiledDRMIntegration.cpp b/src/backend/drm/TiledDRMIntegration.cpp
index 9c9b0cfc5d621d50647557cb02c82182f626cbec..e45ff9df9c20a1f46c925d5da32cdf934cf45482 100644
--- a/src/backend/drm/TiledDRMIntegration.cpp
+++ b/src/backend/drm/TiledDRMIntegration.cpp
@@ -61,6 +61,28 @@ namespace {
             default: return eScanBeginResult::INVALID_STATE;
         }
     }
+
+    struct STerminalShutdownProofs {
+        Aquamarine::NDRM::eTiledRegistryShutdownProof registry = Aquamarine::NDRM::eTiledRegistryShutdownProof::NONE;
+        Aquamarine::NDRM::eTiledRetirementProof       runtime  = Aquamarine::NDRM::eTiledRetirementProof::NONE;
+    };
+
+    std::optional<STerminalShutdownProofs> terminalShutdownProofs(eDetachTerminalProof proof) noexcept {
+        switch (proof) {
+            case eDetachTerminalProof::DRM_DEVICE_GONE:
+                return STerminalShutdownProofs{
+                    .registry = Aquamarine::NDRM::eTiledRegistryShutdownProof::DRM_DEVICE_GONE,
+                    .runtime  = Aquamarine::NDRM::eTiledRetirementProof::DRM_DEVICE_GONE,
+                };
+            case eDetachTerminalProof::BACKEND_OBJECT_DESTRUCTING_NO_CALLBACKS:
+            case eDetachTerminalProof::CALLBACK_INGRESS_NEVER_PUBLISHED:
+                return STerminalShutdownProofs{
+                    .registry = Aquamarine::NDRM::eTiledRegistryShutdownProof::BACKEND_NO_CALLBACKS,
+                    .runtime  = Aquamarine::NDRM::eTiledRetirementProof::BACKEND_TEARDOWN_NO_CALLBACKS,
+                };
+        }
+        return std::nullopt;
+    }
 }
 
 class CTiledDRMIntegrationRegistry::CImpl {
@@ -76,6 +98,9 @@ class CTiledDRMIntegrationRegistry::CImpl {
         Hyprutils::Memory::CUniquePointer<CGroupedRuntimeAuthority> groupedRuntime;
         bool                                                        allocationGateActive = false;
         bool                                                        detachBegun          = false;
+        std::optional<eDetachTerminalProof>                         terminalProof;
+        // Diagnostic context only. terminalizeDetachedKey() never derives an
+        // authorization proof from this value.
         eDetachReason                                               detachReason         = eDetachReason::BACKEND_SHUTDOWN;
     };
 
@@ -1113,7 +1138,7 @@ eDetachResult CTiledDRMIntegrationRegistry::beginTestDetach(const PBackendLifeti
     return beginDetachKey(lifetime.impl_, reason);
 }
 
-eDetachResult CTiledDRMIntegrationRegistry::eraseDetachedKey(const void* key) noexcept {
+eDetachResult CTiledDRMIntegrationRegistry::terminalizeDetachedKey(const void* key, eDetachTerminalProof proof) noexcept {
     const auto THREAD = m_impl->registeredThread(key);
     if (!THREAD)
         return eDetachResult::NOT_ATTACHED;
@@ -1127,11 +1152,40 @@ eDetachResult CTiledDRMIntegrationRegistry::eraseDetachedKey(const void* key) no
         return eDetachResult::BUSY;
     if (!ENTRY->second.detachBegun)
         return eDetachResult::INVALID_STATE;
-    const auto REGISTRY_PROOF =
-        ENTRY->second.detachReason == eDetachReason::GPU_REMOVED ? eTiledRegistryShutdownProof::DRM_DEVICE_GONE : eTiledRegistryShutdownProof::BACKEND_NO_CALLBACKS;
-    const auto RUNTIME_PROOF =
-        ENTRY->second.detachReason == eDetachReason::GPU_REMOVED ? eTiledRetirementProof::DRM_DEVICE_GONE : eTiledRetirementProof::BACKEND_TEARDOWN_NO_CALLBACKS;
-    if (!ENTRY->second.groupedRuntime || !ENTRY->second.groupedRuntime->terminalShutdown(REGISTRY_PROOF, RUNTIME_PROOF))
+
+    const auto PROOFS = terminalShutdownProofs(proof);
+    if (!PROOFS)
+        return eDetachResult::INVALID_STATE;
+    if (ENTRY->second.terminalProof)
+        return eDetachResult::ALREADY_TERMINALIZED;
+    if (!ENTRY->second.groupedRuntime || !ENTRY->second.groupedRuntime->terminalShutdown(PROOFS->registry, PROOFS->runtime))
+        return eDetachResult::INVALID_STATE;
+
+    ENTRY->second.terminalProof = proof;
+    return eDetachResult::TERMINALIZED;
+}
+
+eDetachResult CTiledDRMIntegrationRegistry::terminalizeDetached(const CWeakPointer<CDRMBackend>& backend, eDetachTerminalProof proof) noexcept {
+    return terminalizeDetachedKey(backend.impl_, proof);
+}
+
+eDetachResult CTiledDRMIntegrationRegistry::terminalizeTestDetached(const PBackendLifetime& lifetime, eDetachTerminalProof proof) noexcept {
+    return terminalizeDetachedKey(lifetime.impl_, proof);
+}
+
+eDetachResult CTiledDRMIntegrationRegistry::eraseTerminalizedKey(const void* key) noexcept {
+    const auto THREAD = m_impl->registeredThread(key);
+    if (!THREAD)
+        return eDetachResult::NOT_ATTACHED;
+    if (*THREAD != std::this_thread::get_id())
+        return eDetachResult::WRONG_THREAD;
+
+    const auto ENTRY = m_impl->entries.find(key);
+    if (ENTRY == m_impl->entries.end())
+        return eDetachResult::INVALID_STATE;
+    if (m_impl->mutationBusy(ENTRY->second))
+        return eDetachResult::BUSY;
+    if (!ENTRY->second.detachBegun || !ENTRY->second.terminalProof || !ENTRY->second.groupedRuntime || !ENTRY->second.groupedRuntime->readyForDestruction())
         return eDetachResult::INVALID_STATE;
     if (m_impl->scanRegistry.erase(ENTRY->second.lifetime) != eRegistryResult::OK)
         return eDetachResult::INVALID_STATE;
@@ -1142,12 +1196,12 @@ eDetachResult CTiledDRMIntegrationRegistry::eraseDetachedKey(const void* key) no
     return eDetachResult::DETACHED;
 }
 
-eDetachResult CTiledDRMIntegrationRegistry::eraseDetached(const CWeakPointer<CDRMBackend>& backend) noexcept {
-    return eraseDetachedKey(backend.impl_);
+eDetachResult CTiledDRMIntegrationRegistry::eraseTerminalized(const CWeakPointer<CDRMBackend>& backend) noexcept {
+    return eraseTerminalizedKey(backend.impl_);
 }
 
-eDetachResult CTiledDRMIntegrationRegistry::eraseTestDetached(const PBackendLifetime& lifetime) noexcept {
-    return eraseDetachedKey(lifetime.impl_);
+eDetachResult CTiledDRMIntegrationRegistry::eraseTestTerminalized(const PBackendLifetime& lifetime) noexcept {
+    return eraseTerminalizedKey(lifetime.impl_);
 }
 
 bool CTiledDRMIntegrationRegistry::attachedKey(const void* key) const noexcept {
@@ -1291,9 +1345,14 @@ eDetachResult Aquamarine::NDRM::NTiledDRMIntegration::beginDetach(const CWeakPoi
     return REGISTRY ? REGISTRY->beginDetach(backend, reason) : eDetachResult::NOT_ATTACHED;
 }
 
-eDetachResult Aquamarine::NDRM::NTiledDRMIntegration::eraseDetached(const CWeakPointer<CDRMBackend>& backend) noexcept {
+eDetachResult Aquamarine::NDRM::NTiledDRMIntegration::terminalizeDetached(const CWeakPointer<CDRMBackend>& backend, eDetachTerminalProof proof) noexcept {
     auto* const REGISTRY = productionRegistryIfCreated();
-    return REGISTRY ? REGISTRY->eraseDetached(backend) : eDetachResult::NOT_ATTACHED;
+    return REGISTRY ? REGISTRY->terminalizeDetached(backend, proof) : eDetachResult::NOT_ATTACHED;
+}
+
+eDetachResult Aquamarine::NDRM::NTiledDRMIntegration::eraseTerminalized(const CWeakPointer<CDRMBackend>& backend) noexcept {
+    auto* const REGISTRY = productionRegistryIfCreated();
+    return REGISTRY ? REGISTRY->eraseTerminalized(backend) : eDetachResult::NOT_ATTACHED;
 }
 
 bool Aquamarine::NDRM::NTiledDRMIntegration::attached(const CWeakPointer<CDRMBackend>& backend) noexcept {
diff --git a/src/backend/drm/TiledDRMIntegration.hpp b/src/backend/drm/TiledDRMIntegration.hpp
index 531bc5f3834ed033a84d4409350aa4484568dcc2..226f7138e93e79e81eb20917a7e0c3b724ac89df 100644
--- a/src/backend/drm/TiledDRMIntegration.hpp
+++ b/src/backend/drm/TiledDRMIntegration.hpp
@@ -83,9 +83,20 @@ namespace Aquamarine::NDRM::NTiledDRMIntegration { // NOLINT(readability-identif
         DESTRUCTOR_FALLBACK,
     };
 
+    // Terminal teardown is authorized only by an explicit proof supplied at
+    // the callback-ingress boundary. eDetachReason is diagnostic context and
+    // must never be promoted into one of these proofs.
+    enum class eDetachTerminalProof : uint8_t {
+        DRM_DEVICE_GONE = 0,
+        BACKEND_OBJECT_DESTRUCTING_NO_CALLBACKS,
+        CALLBACK_INGRESS_NEVER_PUBLISHED,
+    };
+
     enum class eDetachResult : uint8_t {
         BEGUN = 0,
         ALREADY_BEGUN,
+        TERMINALIZED,
+        ALREADY_TERMINALIZED,
         DETACHED,
         NOT_ATTACHED,
         WRONG_THREAD,
@@ -230,7 +241,8 @@ namespace Aquamarine::NDRM::NTiledDRMIntegration { // NOLINT(readability-identif
 
         [[nodiscard]] eSessionResult            rotateSession(const CWeakPointer<CDRMBackend>& backend) noexcept;
         [[nodiscard]] eDetachResult             beginDetach(const CWeakPointer<CDRMBackend>& backend, eDetachReason reason) noexcept;
-        [[nodiscard]] eDetachResult             eraseDetached(const CWeakPointer<CDRMBackend>& backend) noexcept;
+        [[nodiscard]] eDetachResult             terminalizeDetached(const CWeakPointer<CDRMBackend>& backend, eDetachTerminalProof proof) noexcept;
+        [[nodiscard]] eDetachResult             eraseTerminalized(const CWeakPointer<CDRMBackend>& backend) noexcept;
 
         [[nodiscard]] bool                      attached(const CWeakPointer<CDRMBackend>& backend) const noexcept;
         [[nodiscard]] bool                      lastConnectorScanComplete(const CWeakPointer<CDRMBackend>& backend) const noexcept;
@@ -245,7 +257,8 @@ namespace Aquamarine::NDRM::NTiledDRMIntegration { // NOLINT(readability-identif
         [[nodiscard]] SBeginConnectorScanResult beginAttached(const void* key);
         [[nodiscard]] eSessionResult            rotateSessionKey(const void* key) noexcept;
         [[nodiscard]] eDetachResult             beginDetachKey(const void* key, eDetachReason reason) noexcept;
-        [[nodiscard]] eDetachResult             eraseDetachedKey(const void* key) noexcept;
+        [[nodiscard]] eDetachResult             terminalizeDetachedKey(const void* key, eDetachTerminalProof proof) noexcept;
+        [[nodiscard]] eDetachResult             eraseTerminalizedKey(const void* key) noexcept;
         [[nodiscard]] bool                      attachedKey(const void* key) const noexcept;
         [[nodiscard]] PCommittedScan            currentCompleteKey(const void* key) noexcept;
         [[nodiscard]] SScanOutcome              outcomeKey(const void* key) noexcept;
@@ -263,7 +276,8 @@ namespace Aquamarine::NDRM::NTiledDRMIntegration { // NOLINT(readability-identif
         [[nodiscard]] SBeginConnectorScanResult beginTestConnectorScan(const PBackendLifetime& lifetime);
         [[nodiscard]] eSessionResult            rotateTestSession(const PBackendLifetime& lifetime) noexcept;
         [[nodiscard]] eDetachResult             beginTestDetach(const PBackendLifetime& lifetime, eDetachReason reason) noexcept;
-        [[nodiscard]] eDetachResult             eraseTestDetached(const PBackendLifetime& lifetime) noexcept;
+        [[nodiscard]] eDetachResult             terminalizeTestDetached(const PBackendLifetime& lifetime, eDetachTerminalProof proof) noexcept;
+        [[nodiscard]] eDetachResult             eraseTestTerminalized(const PBackendLifetime& lifetime) noexcept;
         [[nodiscard]] bool                      testAttached(const PBackendLifetime& lifetime) const noexcept;
         [[nodiscard]] bool                      testLastConnectorScanComplete(const PBackendLifetime& lifetime) const noexcept;
         [[nodiscard]] PCommittedScan            testCurrentComplete(const PBackendLifetime& lifetime) noexcept;
@@ -303,7 +317,8 @@ namespace Aquamarine::NDRM::NTiledDRMIntegration { // NOLINT(readability-identif
                                                                                       uint32_t sequence, uint64_t timestampNs) noexcept;
     [[nodiscard]] AQ_TILED_DRM_PRIVATE eSessionResult            rotateSession(const CWeakPointer<CDRMBackend>& backend) noexcept;
     [[nodiscard]] AQ_TILED_DRM_PRIVATE eDetachResult             beginDetach(const CWeakPointer<CDRMBackend>& backend, eDetachReason reason) noexcept;
-    [[nodiscard]] AQ_TILED_DRM_PRIVATE eDetachResult             eraseDetached(const CWeakPointer<CDRMBackend>& backend) noexcept;
+    [[nodiscard]] AQ_TILED_DRM_PRIVATE eDetachResult             terminalizeDetached(const CWeakPointer<CDRMBackend>& backend, eDetachTerminalProof proof) noexcept;
+    [[nodiscard]] AQ_TILED_DRM_PRIVATE eDetachResult             eraseTerminalized(const CWeakPointer<CDRMBackend>& backend) noexcept;
     [[nodiscard]] AQ_TILED_DRM_PRIVATE bool                      attached(const CWeakPointer<CDRMBackend>& backend) noexcept;
     [[nodiscard]] AQ_TILED_DRM_PRIVATE bool                      lastConnectorScanComplete(const CWeakPointer<CDRMBackend>& backend) noexcept;
     [[nodiscard]] AQ_TILED_DRM_PRIVATE PCommittedScan            currentComplete(const CWeakPointer<CDRMBackend>& backend) noexcept;
diff --git a/tests/TiledDRMIntegration.cpp b/tests/TiledDRMIntegration.cpp
index 27383607b6e90f21aa0d741d67fe7f3d2ccc4530..d32e1b0e225b0c0554246e7e0a616848e011f615 100644
--- a/tests/TiledDRMIntegration.cpp
+++ b/tests/TiledDRMIntegration.cpp
@@ -38,8 +38,12 @@ namespace Aquamarine::NDRM::NTiledDRMIntegrationTest {
             return registry.beginTestDetach(lifetime, reason);
         }
 
+        static eDetachResult terminalize(CTiledDRMIntegrationRegistry& registry, const PBackendLifetime& lifetime, eDetachTerminalProof proof) {
+            return registry.terminalizeTestDetached(lifetime, proof);
+        }
+
         static eDetachResult erase(CTiledDRMIntegrationRegistry& registry, const PBackendLifetime& lifetime) {
-            return registry.eraseTestDetached(lifetime);
+            return registry.eraseTestTerminalized(lifetime);
         }
 
         static bool attached(const CTiledDRMIntegrationRegistry& registry, const PBackendLifetime& lifetime) {
@@ -378,6 +382,16 @@ int main() {
         const auto QUEUED = CFixtureAuthority::begin(registry, LIFETIME);
         EXPECT(!!QUEUED.scan, false);
         EXPECT(value(QUEUED.result), value(eScanBeginResult::INVALID_STATE));
+        EXPECT(value(CFixtureAuthority::erase(registry, LIFETIME)), value(eDetachResult::INVALID_STATE));
+        EXPECT(CFixtureAuthority::attached(registry, LIFETIME), true);
+        EXPECT(value(CFixtureAuthority::outcome(registry, LIFETIME).result), value(eScanOutcome::TEARING_DOWN));
+        EXPECT(value(CFixtureAuthority::terminalize(registry, LIFETIME, eDetachTerminalProof::BACKEND_OBJECT_DESTRUCTING_NO_CALLBACKS)), value(eDetachResult::TERMINALIZED));
+        EXPECT(CFixtureAuthority::attached(registry, LIFETIME), true);
+        EXPECT(value(CFixtureAuthority::outcome(registry, LIFETIME).result), value(eScanOutcome::TEARING_DOWN));
+        EXPECT(registry.readyForDestruction(), false);
+        EXPECT(value(CFixtureAuthority::terminalize(registry, LIFETIME, eDetachTerminalProof::BACKEND_OBJECT_DESTRUCTING_NO_CALLBACKS)),
+               value(eDetachResult::ALREADY_TERMINALIZED));
+        EXPECT(value(CFixtureAuthority::terminalize(registry, LIFETIME, eDetachTerminalProof::DRM_DEVICE_GONE)), value(eDetachResult::ALREADY_TERMINALIZED));
         EXPECT(value(CFixtureAuthority::erase(registry, LIFETIME)), value(eDetachResult::DETACHED));
         EXPECT(CFixtureAuthority::attached(registry, LIFETIME), false);
         EXPECT(registry.readyForDestruction(), true);
@@ -394,6 +408,9 @@ int main() {
         const auto RECOVERED = commitComplete(registry, LIFETIME, 51, ret);
         EXPECT(!!RECOVERED, true);
         EXPECT(value(CFixtureAuthority::beginDetach(registry, LIFETIME, eDetachReason::INITIALIZATION_ABORTED)), value(eDetachResult::BEGUN));
+        EXPECT(value(CFixtureAuthority::terminalize(registry, LIFETIME, static_cast<eDetachTerminalProof>(255))), value(eDetachResult::INVALID_STATE));
+        EXPECT(CFixtureAuthority::attached(registry, LIFETIME), true);
+        EXPECT(value(CFixtureAuthority::terminalize(registry, LIFETIME, eDetachTerminalProof::CALLBACK_INGRESS_NEVER_PUBLISHED)), value(eDetachResult::TERMINALIZED));
         EXPECT(value(CFixtureAuthority::erase(registry, LIFETIME)), value(eDetachResult::DETACHED));
     }
 
@@ -409,7 +426,27 @@ int main() {
         EXPECT(CFixtureAuthority::attached(registry, LIFETIME), true);
         EXPECT(!!CFixtureAuthority::current(registry, LIFETIME), true);
 
+        EXPECT(value(CFixtureAuthority::terminalize(registry, LIFETIME, eDetachTerminalProof::DRM_DEVICE_GONE)), value(eDetachResult::INVALID_STATE));
         EXPECT(value(CFixtureAuthority::beginDetach(registry, LIFETIME, eDetachReason::GPU_REMOVED)), value(eDetachResult::BEGUN));
+        std::atomic<int> wrongTerminalResult = -1;
+        std::atomic<int> wrongEraseResult    = -1;
+        std::thread      wrongTerminal([&] {
+            wrongTerminalResult = value(CFixtureAuthority::terminalize(registry, LIFETIME, eDetachTerminalProof::DRM_DEVICE_GONE));
+            wrongEraseResult    = value(CFixtureAuthority::erase(registry, LIFETIME));
+        });
+        wrongTerminal.join();
+        EXPECT(wrongTerminalResult.load(), value(eDetachResult::WRONG_THREAD));
+        EXPECT(wrongEraseResult.load(), value(eDetachResult::WRONG_THREAD));
+        EXPECT(value(CFixtureAuthority::terminalize(registry, LIFETIME, eDetachTerminalProof::DRM_DEVICE_GONE)), value(eDetachResult::TERMINALIZED));
+        EXPECT(CFixtureAuthority::attached(registry, LIFETIME), true);
+        EXPECT(value(CFixtureAuthority::outcome(registry, LIFETIME).result), value(eScanOutcome::TEARING_DOWN));
+        const auto AFTER_DEVICE_GONE = CFixtureAuthority::begin(registry, LIFETIME);
+        EXPECT(!!AFTER_DEVICE_GONE.scan, false);
+        EXPECT(value(AFTER_DEVICE_GONE.result), value(eScanBeginResult::INVALID_STATE));
+        EXPECT(value(CFixtureAuthority::terminalize(registry, LIFETIME, eDetachTerminalProof::BACKEND_OBJECT_DESTRUCTING_NO_CALLBACKS)),
+               value(eDetachResult::ALREADY_TERMINALIZED));
+        EXPECT(CFixtureAuthority::attached(registry, LIFETIME), true);
+        EXPECT(value(CFixtureAuthority::outcome(registry, LIFETIME).result), value(eScanOutcome::TEARING_DOWN));
         EXPECT(value(CFixtureAuthority::erase(registry, LIFETIME)), value(eDetachResult::DETACHED));
     }
 
@@ -512,6 +549,7 @@ int main() {
         SBeginConnectorScanResult nestedBegin;
         eSessionResult            nestedRotate = eSessionResult::ROTATED;
         eDetachResult             nestedDetach = eDetachResult::BEGUN;
+        eDetachResult             nestedTerminal = eDetachResult::TERMINALIZED;
         eDetachResult             nestedErase  = eDetachResult::DETACHED;
         EXPECT(CFixtureAuthority::withCurrent(registry, LIFETIME, SHADOW,
                                               [&](const CPlan&, const SCurrentState& current) {
@@ -522,6 +560,8 @@ int main() {
                                                   nestedBegin   = CFixtureAuthority::begin(registry, LIFETIME);
                                                   nestedRotate  = CFixtureAuthority::rotate(registry, LIFETIME);
                                                   nestedDetach  = CFixtureAuthority::beginDetach(registry, LIFETIME, eDetachReason::BACKEND_SHUTDOWN);
+                                                  nestedTerminal =
+                                                      CFixtureAuthority::terminalize(registry, LIFETIME, eDetachTerminalProof::BACKEND_OBJECT_DESTRUCTING_NO_CALLBACKS);
                                                   nestedErase   = CFixtureAuthority::erase(registry, LIFETIME);
                                               }),
                true);
@@ -533,6 +573,7 @@ int main() {
         EXPECT(!!nestedBegin.scan, false);
         EXPECT(value(nestedRotate), value(eSessionResult::BUSY));
         EXPECT(value(nestedDetach), value(eDetachResult::BUSY));
+        EXPECT(value(nestedTerminal), value(eDetachResult::BUSY));
         EXPECT(value(nestedErase), value(eDetachResult::BUSY));
         EXPECT(CFixtureAuthority::allocation(registry, LIFETIME) == SHADOW, true);
         EXPECT(CFixtureAuthority::lastComplete(registry, LIFETIME), true);
@@ -639,6 +680,7 @@ int main() {
         EXPECT(!!CFixtureAuthority::outputBridge(registry, LIFETIME), true);
         EXPECT(value(CFixtureAuthority::beginDetach(registry, LIFETIME, eDetachReason::BACKEND_SHUTDOWN)), value(eDetachResult::BEGUN));
         EXPECT(!!CFixtureAuthority::outputBridge(registry, LIFETIME), false);
+        EXPECT(value(CFixtureAuthority::terminalize(registry, LIFETIME, eDetachTerminalProof::BACKEND_OBJECT_DESTRUCTING_NO_CALLBACKS)), value(eDetachResult::TERMINALIZED));
         EXPECT(value(CFixtureAuthority::erase(registry, LIFETIME)), value(eDetachResult::DETACHED));
     }