Add eventual cleanup liveness and fix cancel quiescence gaps.

Encode zero-orphan intent as EventuallyNonWinnerStagingCleaned and
EventuallySystemQuiescent under recovery. Stop authorized attempts on
FinalizeCancel and do not re-publish cancel notices after terminal so fair
behaviors can reach SystemQuiescent (TLC-checked on Remora.cfg).
This commit is contained in:
ms2k 2026-07-10 14:46:55 +09:00
commit 6b6588c5ac
2 changed files with 29 additions and 1 deletions

View file

@ -42,3 +42,5 @@ PROPERTIES
EventuallyDispatched EventuallyDispatched
EventuallyReaped EventuallyReaped
EventuallyTerminal EventuallyTerminal
EventuallyNonWinnerStagingCleaned
EventuallySystemQuiescent

View file

@ -471,18 +471,26 @@ RequestCancel(j) ==
\* Cancelled forbids durable publication; it does not assert process stop. \* Cancelled forbids durable publication; it does not assert process stop.
\* Progress remains until coord GC (ClearStaleLiveProgress / terminal clean). \* Progress remains until coord GC (ClearStaleLiveProgress / terminal clean).
\* Authorized-never-activated attempts stop here so they do not block quiescence.
FinalizeCancel(j) == FinalizeCancel(j) ==
/\ phase[j] = Cancelling /\ phase[j] = Cancelling
/\ phase' = [phase EXCEPT ![j] = Cancelled] /\ phase' = [phase EXCEPT ![j] = Cancelled]
/\ authority' = [authority EXCEPT ![j] = NoAttempt] /\ authority' = [authority EXCEPT ![j] = NoAttempt]
/\ attemptState' =
[a \in AttemptIds |->
IF JobOf(a) = j /\ attemptState[a] = AttemptAuthorized
THEN AttemptStopped ELSE attemptState[a]]
/\ UNCHANGED <<cancelRequested, currentToken, dispatchNeeded, /\ UNCHANGED <<cancelRequested, currentToken, dispatchNeeded,
committedAttempt, checkpoint, checkpointValid>> committedAttempt, checkpoint, checkpointValid>>
/\ UNCHANGED coordinationVars /\ UNCHANGED coordinationVars
/\ UNCHANGED workerVars /\ UNCHANGED workerVars
/\ UNCHANGED attemptVars /\ UNCHANGED <<attemptWorker, attemptProgress, initialProgress,
resumedFromCheckpoint, stageState, pendingOutcome>>
\* In-flight cancel signal only; terminal jobs do not re-arm notice after clean.
PublishCancelNotice(j) == PublishCancelNotice(j) ==
/\ cancelRequested[j] /\ cancelRequested[j]
/\ ~Terminal(j)
/\ ~cancelNotice[j] /\ ~cancelNotice[j]
/\ cancelNotice' = [cancelNotice EXCEPT ![j] = TRUE] /\ cancelNotice' = [cancelNotice EXCEPT ![j] = TRUE]
/\ UNCHANGED durableVars /\ UNCHANGED durableVars
@ -954,6 +962,9 @@ CommitIsFencedCAS == [][CommitLinearizationStep]_vars
\* EventuallyTerminal: some terminal outcome (Succeeded, Failed, or Cancelled). \* EventuallyTerminal: some terminal outcome (Succeeded, Failed, or Cancelled).
\* Permanent source/target failure may yield Failed after the retry budget; success \* Permanent source/target failure may yield Failed after the retry budget; success
\* is not guaranteed under unrestricted WantsFailure nondeterminism. \* is not guaranteed under unrestricted WantsFailure nondeterminism.
\* EventuallyNonWinnerStagingCleaned / EventuallySystemQuiescent: model GC goal under
\* fairness (infallible CleanupStage). Product seeks zero orphans under recovery;
\* not a safety invariant and not a readiness gate (IF-7).
WorkerAvailable(w) == WorkerAvailable(w) ==
/\ workerState[w] = WorkerUp /\ workerState[w] = WorkerUp
/\ \A s \in Services : CanReach(w, s) /\ \A s \in Services : CanReach(w, s)
@ -970,4 +981,19 @@ EventuallyReaped ==
EventuallyTerminal == EventuallyTerminal ==
RecoveryAssumption => \A j \in Jobs : <>Terminal(j) RecoveryAssumption => \A j \in Jobs : <>Terminal(j)
CleanupEligible(a) ==
/\ stageState[a] \in {StagePartial, StageComplete}
/\ committedAttempt[JobOf(a)] # a
/\ ~CurrentAuthority(a)
/\ (attemptState[a] = AttemptStopped
\/ workerState[attemptWorker[a]] = WorkerDown)
EventuallyNonWinnerStagingCleaned ==
RecoveryAssumption =>
\A a \in AttemptIds :
CleanupEligible(a) ~> stageState[a] = StageCleaned
EventuallySystemQuiescent ==
RecoveryAssumption => <>SystemQuiescent
============================================================================= =============================================================================