Skip to main content

Declarative Scheduler Theory


Preamble

This document defines a formal, mathematical theory for declarative schedulers. It is part of the Declarative Scheduler Specification.

Purpose

We tell implementers exactly what must be observable for a scheduler to be correct. We write axioms about starts, ends, initialization, stopping, due/retry pulses, and crashes; we bound progress by the environment's granted compute; and we keep internals out of scope. The result is a portable yardstick for conformance, fairness assumptions, and failure attribution.

The goals are to

  • specify conformance precisely,
  • enable proofs and model checking of behaviors,
  • support portable tests/oracles that attribute responsibility to the scheduler vs. the environment.

Scope

This theory focuses on externally observable behavior of the scheduler, defining:

  • The observable event alphabet and timing semantics
  • Safety and liveness properties that schedulers MUST satisfy
  • The interface contract between scheduler and execution environment

Non-Goals

This specification does not cover:

  • Error-handling implementation details
  • Internal scheduler data structures or algorithms
  • Performance optimization strategies
  • Specific embedding mechanisms in JavaScript runtimes

Mathematical Preliminaries & Notation

We work over timestamped linear traces (iτ(i)T\langle i \mapsto \tau(i) \in \mathbb{T} \rangle) and reason in first-order linear-time temporal logic with past. Variables range over the scheduler’s observable objects and time domain. By convention, formulas without explicit quantifiers are universally quantified. We write RSx\mathrm{RS}_x etc. for instantiated predicates and distinguish environment-owned predicates/functions (clock pulses, crashes, compute/duration) from scheduler-owned actions (starts/ends/init/stop). Quantitative liveness uses compute-bounded modalities, with budgets linear in bit-lengths ( X|X| ) and a fixed lag ( tlagt_{\text{lag}} ). These modalities are definition schemata over the signature.

The universe of scheduler's objects includes all possible objects, not just those present in a particular trace. This means that, for instance, a task with cron expression * * * * * exists.

Time & Traces

  • Time domain: a set T\mathbb{T} used to timestamp observable instants. The timestamps have abstract resolution (i.e., they are not tied to any specific real-world clock). But they do correspond to real time, in the sense that for every real-world instance, there is a corresponding timestamp in T\mathbb{T}.
  • Trace: a sequence of positions i=0,1,2,i = 0, 1, 2, \dots with a timestamp function τ(i)T\tau(i) \in \mathbb{T} that is non-strictly increasing. At each position ii, one or more observable events may occur. Events that are simultaneous appear at the same integer time points. Time bounds are background semantics only (not encoded in LTL). Reference to simultaneity rules is provided in axiom EA3.

LTL with Past

Our formulas are written in linear-time temporal logic with past. We use the following operators:

  • Future operators: G\texttt{G} (□), F\texttt{F} (◊), X\texttt{X} (next), U\texttt{U} (until), W\texttt{W} (weak until).
  • Past operators: H\texttt{H} (historically), O\texttt{O} (once), S\texttt{S} (since), Y\texttt{Y} (previous).

Encodings & Bit-Length Conventions

Encodings and bit-length. Fix a canonical, prefix-free, computable encoding \llbracket\cdot\rrbracket from objects to bitstrings with linear-time decoding. For any object XX, write X:=X|X| := |\llbracket X \rrbracket| for the bit length of its encoding.

Background time value and its size. Each position ii is associated with a background timestamp value t:=τ(i)Tt := \tau(i) \in \mathbb{T}. Define t:=t|t| := |\llbracket t \rrbracket| using a standard signed binary encoding (so this equals 1+log2(1+tabs)1 + \lceil \log_2(1 + |t|_{\text{abs}}) \rceil, where tabs|t|_{\text{abs}} is the absolute value of tt). Important: t|t| measures the value of the clock, not the density of events; events may be sparse in ii even when t|t| grows.

Helper Modalities

Strict compute-bounded eventually

For a given scheduler Scheduler(a,b,tlag)\textsf{Scheduler}(a,b,t_{\texttt{lag}}) and CPC \in \mathbb{P}, the modality

Fcomp!C(P)F^{\leq C}_{\texttt{comp}!}(P)

holds at time τ(i)\tau(i) iff there exists jij \geq i, U=[τ(i),τ(j)]U = [\tau(i), \tau(j)], and SUS \subseteq U such that:

  • PP holds at jj,
  • compute(S)C\texttt{compute}(S) \leq C,
  • duration(US)tlag\texttt{duration}(U \setminus S) \leq t_{\texttt{lag}}.

Intuitively, this asserts that PP will occur after receiving at most CC units of environment-provided compute from the current position, plus a small lag tlagt_{\texttt{lag}} to account for a constant delay.

This is the strict progress condition that attributes all delay to the scheduler except for the fixed lag in its witnesses.

In typical usage, CC is a finite value derived from the scheduler's complexity bounds, though the definition permits C=C = \infty.

Compute-bounded eventually

At time τ(i)\tau(i) and for CPC \in \mathbb{P},

GrantC  :=  ji.  compute([τ(i),τ(j)])C.\texttt{Grant}_{\ge C} \;:=\; \exists j \ge i.\; \texttt{compute}\big([\tau(i), \tau(j)]\big) \ge C.

Intuitively, once GrantC\texttt{Grant}_{\ge C} holds, the environment will cumulatively offer at least CC units of compute starting at the current instant.

FcompC(P)  :=  GrantCFcomp!C(P)F^{\le C}_{\texttt{comp}}(P) \;:=\; \texttt{Grant}_{\ge C} \Rightarrow F^{\le C}_{\texttt{comp}!}(P)

The regular modality only promises progress when the environment has the potential to provide at least CC units of compute from the current instant onward.

Linear-in-input compute bound

For a given scheduler Scheduler(a,b,tlag)\textsf{Scheduler}(a,b,t_{\texttt{lag}}), define:

Fcomplin(X)  :=  Fcomp  aX+bF^{\texttt{lin}(X)}_{\texttt{comp}} \;:=\; F^{\le\; a\cdot|X|+b}_{\texttt{comp}}

A natural extension is to multiple inputs:

Fcomplin(X1,,Xn)  :=  Fcomplin(X1,,Xn)F^{\texttt{lin}(X_1,\dots,X_n)}_{\texttt{comp}} \; := \; F^{\texttt{lin}(\langle X_1,\dots,X_n\rangle)}_{\texttt{comp}}

Domains & Data Types

  • T:=Z\mathbb{T} := \mathbb{Z} — the time domain.
  • D:=Z0\mathbb{D} := \mathbb{Z_{\geq 0}} — the domain of durations.
  • P:=Z0{}\mathbb{P} := \mathbb{Z_{\geq 0}} \cup \{\infty\} — the domain of compute.
  • TaskId\texttt{TaskId} — a set of public task identifiers.
  • Opaque\texttt{Opaque} — a set of uninterpreted atoms where only equality is meaningful.
  • Callback\texttt{Callback} — the set of externally observable callback behaviours (abstracted here to equality).
  • Schedule\texttt{Schedule} — an abstract object interpreted by the predicate Due(schedule:Schedule,t:T)Bool\texttt{Due}(\texttt{schedule}: \texttt{Schedule}, t: \mathbb{T}) \to \texttt{Bool} indicating minute-boundary instants when a task is eligible to start.
  • RetryDelay:=D\texttt{RetryDelay} := \mathbb{D} — non-negative time durations.
  • Task:=TaskId×Schedule×Callback×RetryDelay×Opaque\texttt{Task} := \texttt{TaskId} \times \texttt{Schedule} \times \texttt{Callback} \times \texttt{RetryDelay} \times \texttt{Opaque} with projections id\textsf{id}, sch\textsf{sch}, cb\textsf{cb}, rd\textsf{rd}, key\textsf{key}.
  • RegistrationList\texttt{RegistrationList} — a finite ordered list R=x1,,xnR = \langle x_1,\dots,x_{n} \rangle of tasks. Indexing uses R[i]R[i] for 1in1 \le i \leq n and strong list membership xlistR    i.  R[i]=xx \in_{\text{list}} R \iff \exists i.\; R[i] = x.
  • ValidRegistrations\texttt{ValidRegistrations} — a set of valid registration lists.
  • S\mathbb{S} — an abstract domain of supernatural phenomenon types.

Interpretation

TaskId\texttt{TaskId} names externally visible tasks. A Task\texttt{Task} is the raw 4-tuple provided at registration time, plus the Opaque\texttt{Opaque} value, where key(x)\textsf{key}(x) is an equality-only argument attached to that tuple so the specification can refer to that exact instance without implying pointer semantics or constraining key generation or reuse. The key is not explicitly passed into registration, and it is not directly observable by scheduler implementations.

Due\texttt{Due} and RetryDelay\texttt{RetryDelay} are parameters determined by the environment (host clock); they are not hidden internal state. Time units for Due\texttt{Due} and RetryDelay\texttt{RetryDelay} coincide.

A RegistrationList\texttt{RegistrationList} is the public input provided at initialization; its order and multiplicities are significant, and duplicate identifiers may appear both within a single list and across successive initializations. Duplicate tasks are also possible in a list.

The list ValidRegistrations\texttt{ValidRegistrations} is an environment truth. The scheduler must handle any RValidRegistrationsR \in \texttt{ValidRegistrations}. Even though duplicates are possible in a registration list, the ValidRegistrations\texttt{ValidRegistrations} has those lists excluded. Therefore, the scheduler must reject any list with duplicates. This is to model the situation where users may supply lists with duplicates, but they are invalid and must be rejected.

Durations in D\mathbb{D} correspond to some real-world durations. For example, it could be that duration([0,999])\texttt{duration}([0, 999]) is one hour.

Elements of S\mathbb{S} represent different kinds of unmodelled events. The internal structure of S\mathbb{S} is uninterpreted. This set may include ordinary events like sunsets, user interactions, or rare ones, like cosmic rays that flip RAM bits - anything that exists in reality but isn't part of our formal scheduler/environment vocabulary. To recognize which things constitute supernatural phenomena, see the Classification of Supernatural Phenomena.

Helper Equalities on Tasks

Define id-only equality for raw tasks by xy    id(x)=id(y)x \approx y \iff \textsf{id}(x) = \textsf{id}(y).

Lift this pointwise to registration lists with RR    R=Ri.  R[i]R[i]R \approx R' \iff |R| = |R'| \wedge \forall i.\; R[i] \approx R'[i].


Observable Alphabet

Each event predicate is evaluated at a trace position ii (we omit ii when clear from context):


  • InitStart(R)\texttt{InitStart}(R) — the JavaScript interpreter calls initialize(...). The effective registration set is RR.

  • InitSuccess(R)\texttt{InitSuccess}(R) — the initialize(...) call returns normally. The effective registration set is RR.

  • InitFailure(R)\texttt{InitFailure}(R) — the initialize(...) call throws an error. The effective registration set is RR.

  • StopStart\texttt{StopStart} — the JavaScript interpreter calls stop().

  • StopEnd\texttt{StopEnd} — the stop() call returns.

  • RunStart(x)\texttt{RunStart}(x) — the public callback of task xx is called.

  • RunSuccess(x)\texttt{RunSuccess}(x) — an invocation completes and returns normally.

This event is an environment-supplied truth that occurs when the callback returns without throwing. It cannot be caused or prevented by the scheduler. The scheduler may not know whether the callback will succeed or fail or loop forever.


  • RunFailure(x)\texttt{RunFailure}(x) — an invocation ends by throwing an error.

This event is an environment-supplied truth that occurs when the callback returns by throwing an error. It cannot be caused or prevented by the scheduler. The scheduler may not know whether the callback will succeed or fail or loop forever.


  • UnexpectedShutdown\texttt{UnexpectedShutdown} — an unexpected, in-flight system shutdown occurs (e.g., process or host crash). This interrupts running callbacks and preempts further starts until a subsequent IE\texttt{IE}.

This predicate is supplied by the environment's crash generator. It is not controlled by the scheduler. The scheduler may not know when a crash will occur.


  • supernatural:TP(S)\texttt{supernatural}: \mathbb{T} \to \mathcal{P}(\mathbb{S}) — a function mapping each time instant to the set of supernatural phenomenon types occurring at that instant.

Interpretation: This function classifies supernatural events by their types. At each time tt, supernatural(t)\texttt{supernatural}(t) returns the set of supernatural phenomenon types present at that instant. When supernatural(t)=\texttt{supernatural}(t) = \emptyset, no supernatural events occur at time tt.


  • Duex\texttt{Due}_x — is start of a minute that the cron schedule for task xx matches.

Interpretation: the cron schedule for xx matches the start of a civil minute according to the host system's local clock.

For example, for a cron expression * * * * *, a due fires at 2024-01-01T12:34:00 local time, at the exact start of that minute.

Important: task does not have to be registered for Duex\texttt{Due}_x to occur.

Note: because of DST and other irregularities of a civil clock, minute starts are not uniformly spaced in T\mathbb{T}.


  • RetryDuex\texttt{RetryDue}_x — is the instant when the backoff for a failure of xx expires.

    It is formally defined as:

    RetryDuex at i:=(REfx at j)j  (τ(j)+rd(x)=τ(i))\texttt{RetryDue}_x \texttt{ at } i :=(\texttt{REf}_x \texttt{ at } j) \land \exists_{j} \; \Big(\tau(j) + \textsf{rd}(x) = \tau(i)\Big)

Interpretation: is a primitive point event (like Duex\texttt{Due}_x), supplied by the environment/clock. If the latest RunFailure(x)\texttt{RunFailure}(x) occurs at time tft_f, then RetryDuex\texttt{RetryDue}_x holds at time tf+rd(x)t_f + \textsf{rd}(x). These pulses are truths about the environment.


Each predicate marks the instant the named public action occurs from the perspective of the embedding JavaScript runtime: function entry (InitStart\texttt{InitStart}, StopStart\texttt{StopStart}), function return (IE\texttt{IE}, StopEnd\texttt{StopEnd}), callback invocation begin/end (RunStart\texttt{RunStart}, RE\texttt{RE}), and exogenous crash (UnexpectedShutdown\texttt{UnexpectedShutdown}). No logging or internal bookkeeping is modeled.

Macros

Abbreviations

  • ISR:=InitStart(R)\texttt{IS}_R := \texttt{InitStart}(R)
  • IEsR:=InitSuccess(R)\texttt{IEs}_R := \texttt{InitSuccess}(R)
  • IEfR:=InitFailure(R)\texttt{IEf}_R := \texttt{InitFailure}(R)
  • IER:=IEsRIEfR\texttt{IE}_R := \texttt{IEs}_R \vee \texttt{IEf}_R
  • IEs:=R.  IEsR\texttt{IEs} := \exists R . \; \texttt{IEs}_R
  • IEf:=R.  IEfR\texttt{IEf} := \exists R . \; \texttt{IEf}_R
  • IE:=R.  IER\texttt{IE} := \exists R . \; \texttt{IE}_R
  • SS:=StopStart\texttt{SS} := \texttt{StopStart}
  • SE:=StopEnd\texttt{SE} := \texttt{StopEnd}
  • Crash:=UnexpectedShutdown\texttt{Crash} := \texttt{UnexpectedShutdown}
  • RSx:=RunStart(x)\texttt{RS}_x := \texttt{RunStart}(x)
  • REsx:=RunSuccess(x)\texttt{REs}_x := \texttt{RunSuccess}(x)
  • REfx:=RunFailure(x)\texttt{REf}_x := \texttt{RunFailure}(x)
  • REx:=REsxREfx\texttt{RE}_x := \texttt{REs}_x \vee \texttt{REf}_x

Stateful

  • Hold(set,clear):=((¬clear)  S  set)¬clear\texttt{Hold}(\texttt{set}, \texttt{clear}) := \Big((\neg \texttt{clear}) \; \texttt{S} \; \texttt{set}\Big) \land \neg \texttt{clear}

There was a set\texttt{set} in the past (or now), and no clear\texttt{clear} since.

This is a strict version - if clear and set occur simultaneously, the result is false.


  • Hold+(set,clear):=Hold(set,clear)set\texttt{Hold}^{+}(\texttt{set}, \texttt{clear}) := \texttt{Hold}(\texttt{set}, \texttt{clear}) \lor \texttt{set}

An inclusive version of Hold\texttt{Hold} - if set and clear occur simultaneously, the result is true.


  • AtMostOne(B,A):=G(A X(¬A  W  B))\texttt{AtMostOne}(B, A) := \texttt{G} \Big(A \rightarrow \ \texttt{X} (\neg A \; \texttt{W} \; B ) \Big)

At most one AA between consecutive BB's. One single AA is allowed if there is no next BB.


  • MinuteStart:=x  Duex\texttt{MinuteStart} := \exists_x \; \texttt{Due}_x

Starts of civil minutes.

To see why this definition works, note that every minute boundary in the civil clock induces a Due\texttt{Due} pulse for the cron expression * * * * *. Because that expression is contained within every other expression, whenever any task becomes due, the wildcard expression is also due. Conversely, the wildcard expression is defined precisely for minute starts. Therefore the existential over all tasks captures exactly the instants that are the start of a minute.


  • MountainDuex:=(¬MinuteStart)  S  Duex\texttt{MountainDue}_x := (\neg \texttt{MinuteStart}) \; \texttt{S} \; \texttt{Due}_x

This macro holds continuously from the instant of Duex\texttt{Due}_x until, but not including, the next MinuteStart\texttt{MinuteStart}.

Effectively this keeps the duty cycle "high" for the entire minute. The past-time S\texttt{S} operator requires that the most recent Duex\texttt{Due}_x occurred before the current position and that no MinuteStart\texttt{MinuteStart} has happened since, which means MountainDuex\texttt{MountainDue}_x is true exactly while the civil minute that began with Duex\texttt{Due}_x is still in progress.


  • RegisteredR:=Hold(IEsR,IEs)\texttt{Registered}_{R} := \texttt{Hold}(\texttt{IEs}_{R}, \texttt{IEs})

Reference to the most recent successful initialization of a specific registration list RR.


  • RegisteredR,x:=RegisteredRxlistR\texttt{Registered}_{R, x} := \texttt{Registered}_{R} \land x\in_\text{list}R

Membership of xx in the most recent observed registration list.

Note that this does not imply Active\texttt{Active}.


  • RegisteredR,x:=xx    RegisteredR,x\texttt{Registered}^{\approx}_{R, x} := \exists_{x' \approx x} \; \; \texttt{Registered}_{R, x'}

A weaker version of Register\texttt{Register} that considers only task identifier, not the full task tuple.


  • SSR:=SSRegisteredR\texttt{SS}_R := \texttt{SS} \land \texttt{Registered}_R

Stop started for a specific registration list RR.


  • SER:=SERegisteredR\texttt{SE}_R := \texttt{SE} \land \texttt{Registered}_R

Stop ended for a specific registration list RR.


  • FirstComingx:=(R.  RegisteredR,x)¬(R.  (Y  RegisteredR,x))\texttt{FirstComing}_x := (\exists R . \; \texttt{Registered}^{\approx}_{R, x}) \wedge \neg \Big(\exists R . \; (\texttt{Y} \; \texttt{Registered}^{\approx}_{R, x})\Big)

The moment of appearance of task named id(x)\textsf{id}(x) such that it was not present in the previous registration list.

Note that the comparison is by identifiers, not by full task tuple.

This property allows completely "forgetting" a task after it has been removed instead of tracking its retry/due states forever.


  • ActiveR:=Hold(IEsR,SSRCrashIEs)\texttt{Active}_R := \texttt{Hold}(\texttt{IEs}_R, \texttt{SS}_R \vee \texttt{Crash} \vee \texttt{IEs})

True for an active registration list RR. Determines boundary of when tasks in RR can start. The last disjunct ensures that ActiveR\texttt{Active}_R becomes false if a new initialization occurs (which can only succeed after the current one has stopped or crashed, per the concurrent initialization restriction).


  • Runningx:=Hold(RSx,RExCrash)\texttt{Running}_x := \texttt{Hold}(\texttt{RS}_x, \texttt{RE}_x \lor \texttt{Crash})

An invocation of xx has begun and has not finished before the current position.


  • InitializingR:=Hold(ISR,IERCrash)\texttt{Initializing}_R := \texttt{Hold}(\texttt{IS}_R, \texttt{IE}_R \lor \texttt{Crash})

The scheduler is currently initializing with registration list RR.


  • Quiescent:=¬y.  Runningy\texttt{Quiescent} := \neg \exists y.\; \texttt{Running}_y

No callbacks are currently running.


  • FirstQuiescentSince(σ):=Quiescent(¬Quiescent  S  σ)\texttt{FirstQuiescentSince}(\sigma) := \texttt{Quiescent} \wedge (\neg \texttt{Quiescent} \; \texttt{S} \; \sigma)

The first instant at or after σ\sigma when the system becomes quiescent.


  • Orphanedx:=CrashHold(RSx,REx)\texttt{Orphaned}_x := \texttt{Crash} \wedge \texttt{Hold}(\texttt{RS}_x, \texttt{RE}_x)

An interruption of task xx by a crash.


  • RSuccx:=RSx(¬(REfxCrash)  U  REsx)\texttt{RSucc}_x := \texttt{RS}_x \wedge \Big( \neg (\texttt{REf}_x \lor \texttt{Crash}) \; \texttt{U} \; \texttt{REs}_x \Big)

A start of run that eventually completes successfully (not preempted by failure or crash).


  • IFailR:=ISR(¬IEsR  U  IEfR)\texttt{IFail}_R := \texttt{IS}_R \wedge \Big( \neg \texttt{IEs}_R \; \texttt{U} \; \texttt{IEf}_R \Big)

A start of initialization that eventually throws an error.


  • DuePendingx:=Hold+(Duex,RSxFirstComingx)¬Runningx\texttt{DuePending}_x := \texttt{Hold}^{+}( \texttt{Due}_x, \texttt{RS}_x \lor \texttt{FirstComing}_x ) \wedge \neg \texttt{Running}_x

An outstanding request to perform a start after a due tick, cleared by a start and by FirstComingx\texttt{FirstComing}_x. But the task is not pending if it is currently running.

The reason that FirstComingx\texttt{FirstComing}_x clears DuePendingx\texttt{DuePending}_x is that the scheduler should not start all tasks at once after the first initialization - not to overwhelm the system.


  • RetryPendingx:=Hold+(RetryDuex,RSxFirstComingx)¬Runningx\texttt{RetryPending}_x := \texttt{Hold}^{+}( \texttt{RetryDue}_x, \texttt{RS}_x \lor \texttt{FirstComing}_x) \wedge \neg \texttt{Running}_x

A retry request exists after a failure and persists until it is retried.

Similarly to DuePendingx\texttt{DuePending}_x, the task is not retry-pending if it is currently running.

Similarly to DuePendingx\texttt{DuePending}_x, FirstComingx\texttt{FirstComing}_x clears RetryPendingx\texttt{RetryPending}_x.


  • OrphanedPendingx:=Hold(Orphanedx,RSxFirstComingx)\texttt{OrphanedPending}_x := \texttt{Hold}( \texttt{Orphaned}_x, \texttt{RS}_x \lor \texttt{FirstComing}_x )

A task xx that was interrupted by a crash and has not yet been restarted.


  • BootDuePendingx:=FirstComingxMountainDuex¬Runningx\texttt{BootDuePending}_x := \texttt{FirstComing}_x \land \texttt{MountainDue}_x \land \neg \texttt{Running}_x

Task xx has just appeared and the current civil minute is one when xx is due - so it is pending unless already running.


  • Pendingx:=DuePendingxRetryPendingxOrphanedPendingxBootDuePendingx\texttt{Pending}_x := \texttt{DuePending}_x \vee \texttt{RetryPending}_x \vee \texttt{OrphanedPending}_x \vee \texttt{BootDuePending}_x

A task xx is ready to run.

Note that when task failed but is not retry-due yet, it can still be pending because of due or boot-due.


  • ObligationR,x:=PendingxRegisteredR,xActiveR\texttt{Obligation}_{R, x} := \texttt{Pending}_x \wedge \texttt{Registered}_{R, x} \wedge \texttt{Active}_{R}

The scheduler should actually start task xx now.


  • Obligationx:=R.  ObligationR,x\texttt{Obligation}_{x} := \exists R . \; \texttt{Obligation}_{R, x}

An abbreviation.


Environment

The scheduler operates against an abstract Environment E\mathcal{E}.

The environment is an orthogonal concern to the scheduler design; it is a source of non-determinism that influences observable behaviour.

This section is informative. The formulas enumerated here are axioms about the environments we target:

  • All formal statements in this section are truths about environments in scope.
  • All possible real-world environments in scope satisfy these statements.
  • Implementors need not prove these axioms; the task is to map environments to this theory.

Some environments make it impossible to implement a useful scheduler (for example, permanently freezing environments), but for all environments there exist conformant schedulers. The value of this section is to clarify the blame assignment between scheduler and environment.

Among others, environments contribute these ingredients:

  1. Crash generator — a predicate Crash\texttt{Crash} over trace positions. When true, the environment marks an exogenous interruption that preempts in-flight callbacks and halts the scheduler itself; axiom EA1 enforces the resulting quiescence in the trace.

  2. Compute event predicate — a predicate Compute\texttt{Compute} over trace positions indicating instants when the environment could execute one microinstruction of the scheduler implementation. This is an environment-owned primitive that marks opportunities for scheduler progress.

    From this predicate, we derive the compute function:

    compute(S):={τ(i)SCompute at i}\texttt{compute}(S) := |\{ \tau(i) \in S \mid \texttt{Compute} \texttt{ at } i \}|

    which counts how many compute events occur within a set STS \subseteq \mathbb{T} of time points. The result is in P=Z0{}\mathbb{P} = \mathbb{Z}_{\geq 0} \cup \{\infty\} (the count may be infinite for unbounded sets).

    Compute events are only spent on scheduler's actions. So, in particular, these do not require or "consume" compute events:

    • IO operations,
    • scheduler's sleeping or waiting,
    • garbage collection,
    • progress of callbacks (except for starting and ending them),
    • other activity of the embedding JavaScript runtime.

    More specifically, Compute\texttt{Compute} marks the potential for executing the scheduler's own code (and of its JavaScript dependencies), not anything else.

    It is expected that the scheduler will have access to fewer compute events when more callbacks are running, but this is a very vague assumption, so not formalising it here.

Core Environment Axioms

The statements in this section constitute the theory TenvT_{\textsf{env}}.


EA1 — Busy crashing

G(CrashFrozen)\texttt{G}( \texttt{Crash} \rightarrow \texttt{Frozen} )

No work progresses around a crash instant.


EA2 - Actions require work

G(RExUnfrozen)G(RSxUnfrozen)G(ISRUnfrozen)G(IEUnfrozen)G(SSUnfrozen)G(SEUnfrozen)\texttt{G}( \texttt{RE}_x \rightarrow \texttt{Unfrozen} ) \\ \texttt{G}( \texttt{RS}_x \rightarrow \texttt{Unfrozen} ) \\ \texttt{G}( \texttt{IS}_R \rightarrow \texttt{Unfrozen} ) \\ \texttt{G}( \texttt{IE} \rightarrow \texttt{Unfrozen} ) \\ \texttt{G}( \texttt{SS} \rightarrow \texttt{Unfrozen} ) \\ \texttt{G}( \texttt{SE} \rightarrow \texttt{Unfrozen} ) \\

Observable events, including end of a callback, require that some work has been spent on them.

Importantly, Duex\texttt{Due}_x and RetryDuex\texttt{RetryDue}_x are not included here, as they are primitive truths about the environment, not actions.


EA3 - No simultaneous actions

For any two actions AB, and any different R,x in {REx,RSx,ISR,IE,SS,SE}, we have:G(A¬B)\text{For any two actions } A \neq B, \text{ and any different } R, x \text{ in } \{ \texttt{RE}_x, \texttt{RS}_x, \texttt{IS}_R, \texttt{IE}, \texttt{SS}, \texttt{SE} \}, \text{ we have:} \\ \texttt{G}( A \rightarrow \neg B ) \\

Two actions cannot happen simultaneously.


EA4 - Unlimited freeze

G  F  Frozen\texttt{G} \; \texttt{F} \; \texttt{Frozen}

There are infinitely many intervals of time during which no work progresses. This asserts "density" of time within compute.


EA5 - Unlimited dues

G(F  Duex)G(¬Duex)\texttt{G} ( \texttt{F} \; \texttt{Due}_x) \lor \texttt{G}(\neg \texttt{Due}_x)

For every task xx, the cron schedule matches infinitely often or never at all.

This comes from the fact that cron schedules are periodic and unbounded in time. It is impossible to have a valid cron expression that matches only finitely many times.


EA6 — Crash/RE consistency

G(Crash(¬REx  W  RSx))\texttt{G}\Big( \texttt{Crash} \rightarrow (\neg \texttt{RE}_x \; \texttt{W} \; \texttt{RS}_x) \Big)

After a Crash\texttt{Crash}, no new ends until a new start.


EA7 — Ends follow starts

G(RExY  Runningx)G(IEY  Hold(IS,IECrash))G(SEY  Hold(SS,SECrash))\texttt{G}( \texttt{RE}_x \rightarrow \texttt{Y} \; \texttt{Running}_x) \\ \texttt{G}( \texttt{IE} \rightarrow \texttt{Y} \; \texttt{Hold}(\texttt{IS}, \texttt{IE} \vee \texttt{Crash}) ) \\ \texttt{G}( \texttt{SE} \rightarrow \texttt{Y} \; \texttt{Hold}(\texttt{SS}, \texttt{SE} \vee \texttt{Crash}) ) \\

Every completion must correspond to a prior start.

Environment Taxonomy

The following labels identify illustrative environment classes:

  • Freezing environments: admit arbitrarily long intervals (t,u)(t,u) with Frozen(t,u)\texttt{Frozen}(t, u) (i.e., no Compute\texttt{Compute} events).

  • Eventually thawing environments: there exists UU such that every interval of length U\ge U contains at least one Compute\texttt{Compute} event.

  • Lower-bounded-density environments: there exist parameters ε>0\varepsilon > 0 and Δ0\Delta \ge 0 such that for all tt and TΔT \ge \Delta, compute([t,t+T])εT\texttt{compute}([t,t+T]) \ge \varepsilon\cdot T (average density of Compute\texttt{Compute} events after Δ\Delta never drops below ε\varepsilon).

  • Burst environments: concentrate Compute\texttt{Compute} events in sporadic spikes; for every MM there are intervals of length >M> M with arbitrarily few Compute\texttt{Compute} events alternating with brief, high-density bursts.


Scheduler Axioms

The formulas in this section constitute the theory Tsch(a,b,tlag)T_{\textsf{sch}}(a,b,t_{\texttt{lag}}). Each axiom is parameterised by the witnesses (a,b,tlag)(a,b,t_{\texttt{lag}}) that appear in the compute-bounded modalities.

Safety Axioms

These axioms state scheduler invariants and prevent invalid sequences of events.


S1 — Start safety

G(RSxY  Obligationx)\texttt{G}( \texttt{RS}_x \rightarrow \texttt{Y} \; \texttt{Obligation}_{x} )

A run can occur only after an obligation to run.


S2 — Conservation of starts

AtMostOne(Duex,RSuccx)\texttt{AtMostOne}(\texttt{Due}_x, \texttt{RSucc}_x)

Should prevent multiple successful executions per single due period.


S3 — StopEnd consistency

G(SE¬Runningx)\texttt{G}( \texttt{SE} \rightarrow \neg \texttt{Running}_x)

This means that call to stop() waits for in-flight callbacks to complete.


S4 — Registration soundness

RValidRegistrations    G(¬IEsR)R \notin \texttt{ValidRegistrations} \implies \texttt{G}( \neg \texttt{IEs}_R ) \\

The scheduler must reject any registrations not from the set of valid registrations.

S5 - Registration completeness

RValidRegistrations    G(IFailRR.  Y  InitializingR)R \in \texttt{ValidRegistrations} \implies \texttt{G}( \texttt{IFail}_R \rightarrow \exists R'. \; \texttt{Y} \; \texttt{Initializing}_{R'} ) \\

The scheduler must accept any registrations from the set of valid registrations, unless a concurrent initialization was in progress.


S6 — No concurrent initialization

AtMostOne(IEs,SECrash)\texttt{AtMostOne}(\texttt{IEs}, \texttt{SE} \vee \texttt{Crash})

After a successful initialization, no other initialization can succeed until after a stop or crash.

This ensures that initialize() calls made while the scheduler is in the "running" state result in IEf (thrown error), not IEs.

Liveness Axioms

These normative axioms state progress guarantees. They prevent deadlocks, starvation, livelocks, and unbounded postponement of obligations.

Progress is always read relative to the environment's willingness to provide compute. In fully freezing environments (see Environment taxonomy), obligations may accumulate without violating safety; in eventually thawing or lower-bounded-density environments, the fairness assumptions below become reasonable or derivable premises for liveness. In other words, in some environments, a conformant scheduler may be useless.


L1 — Obligation fulfillment

G(ObligationR,xFcomplin(R,τ(i))(RSx¬ActiveR))\texttt{G}\Big( \texttt{Obligation}_{R, x} \rightarrow \texttt{F}_{\texttt{comp}}^{\texttt{lin}(R, \,\tau(i))} (\texttt{RS}_x \vee \neg \texttt{Active}_R )\Big)

When a task is supposed to be executed, we must eventually see that execution in the form of RSx\texttt{RS}_x (or a Crash\texttt{Crash}, or SS\texttt{SS}).

Furthermore, that execution occurs within a bounded compute (as a linear function of the sizes of the current registration list and timestamp) after the obligation arises, provided the environment actually grants that much compute from the current point onward.


L2 — Initialization completes

G(ISRFcomplin(R,τ(i))  (IERCrash))\texttt{G}\Big( \texttt{IS}_R \rightarrow \texttt{F}_{\texttt{comp}}^{\texttt{lin}(R, \,\tau(i))} \; (\texttt{IE}_R \lor \texttt{Crash}) \Big)

Similar to L1, this property ensures that once an initialization starts, it must eventually complete within a bounded amount of compute (unless preempted by a crash) whenever the environment supplies that budget.


L3 — Stop completes after quiescence

G(SSR    G(FirstQuiescentSince(SSR)    Fcomplin(R,τ(i))(SER    Crash)))\texttt{G}\Big(\, \texttt{SS}_R \;\rightarrow\; \texttt{G}\big(\, \texttt{FirstQuiescentSince}(\texttt{SS}_R) \;\rightarrow\; F_{\texttt{comp}}^{\texttt{lin}(R,\, \tau(i))}( \texttt{SE}_R \;\lor\; \texttt{Crash}) \big)\Big)

Interpretation. After SSR\texttt{SS}_R, as soon as the system first becomes quiescent (no callbacks running), the scheduler must complete stop() within a compute budget linear in the sizes of the registration list and current timestamp (modulo environment grants), or else be pre-empted by Crash\texttt{Crash}.


Structures & Satisfaction

Signature & Structures

We work over a multi-sorted first-order signature Σsch\Sigma_{\textsf{sch}} with the following sorts:

  • T\mathbb{T} (timestamps), D\mathbb{D} (durations), P\mathbb{P} (compute budgets), and S\mathbb{S} (supernatural phenomenon types).
  • TaskId\texttt{TaskId}, Opaque\texttt{Opaque}, Callback\texttt{Callback}, Schedule\texttt{Schedule}, RetryDelay\texttt{RetryDelay}, Task\texttt{Task}, and RegistrationList\texttt{RegistrationList}.
  • Auxiliary finite sets such as ValidRegistrations\texttt{ValidRegistrations} and Boolean values B\mathbb{B}.

Function symbols include:

  • τ:NT\tau : \mathbb{N} \to \mathbb{T} (timestamp map over trace positions).
  • duration:P(T)D\texttt{duration} : \mathcal{P}(\mathbb{T}) \to \mathbb{D} and compute:P(T)P\texttt{compute} : \mathcal{P}(\mathbb{T}) \to \mathbb{P} (where compute\texttt{compute} is defined via the Compute\texttt{Compute} predicate as described in Environment Axioms).
  • supernatural:TP(S)\texttt{supernatural} : \mathbb{T} \to \mathcal{P}(\mathbb{S}) (mapping time instants to sets of supernatural phenomenon types).
  • Task projections id\textsf{id}, sch\textsf{sch}, cb\textsf{cb}, rd\textsf{rd}, key\textsf{key}, list operations (length, indexing), and the environment parameters Due\texttt{Due}, RetryDue\texttt{RetryDue}.

Predicate symbols cover the observable alphabet. They include scheduler-owned atoms ISR\texttt{IS}_R, IE\texttt{IE}, SS\texttt{SS}, SE\texttt{SE}, RSx\texttt{RS}_x, REsx\texttt{REs}_x, REfx\texttt{REf}_x, as well as environment-owned atoms such as Compute\texttt{Compute}, Crash\texttt{Crash}, Duex\texttt{Due}_x, and RetryDuex\texttt{RetryDue}_x, and the standalone supernatural predicate Supernatural\texttt{Supernatural}. Indexed predicates range over the appropriate sorts (e.g., xx ranges over Task\texttt{Task}, RR over RegistrationList\texttt{RegistrationList}); SS\texttt{SS} and SE\texttt{SE} are 0-ary.

The free constants (a,b,tlag)(a,b,t_{\texttt{lag}}) are theory parameters that instantiate compute-bounded modalities within Tsch(a,b,tlag)T_{\textsf{sch}}(a,b,t_{\texttt{lag}}).

An environment is packaged as the tuple

E=Compute,Crash,Duex,RetryDuex,REs,REf,SS,ISR\mathcal{E} = \langle \texttt{Compute}, \texttt{Crash}, \texttt{Due}_x, \texttt{RetryDue}_x, \texttt{REs}, \texttt{REf}, \texttt{SS}, \texttt{IS}_R \rangle

providing the interpretations for environment-owned predicates listed above. The compute\texttt{compute} function is then derived from Compute\texttt{Compute} by counting.

A scheduler behavior is similarly packaged as

S=IER,SE,RSx\mathcal{S} = \langle \texttt{IE}_R, \texttt{SE}, \texttt{RS}_x \rangle

providing the interpretations for scheduler-owned predicates.

The supernatural function is packaged as

N=supernatural\mathcal{N} = \langle \texttt{supernatural} \rangle

providing the interpretation for the function mapping time instants to sets of supernatural phenomenon types that exist outside the theory's formal scope.

ownership note. We classify predicate symbols by ownership: environment-owned predicates are interpreted directly from the environment tuple E\mathcal{E}, while scheduler-owned predicates are produced by the scheduler behavior S\mathcal{S}. The supernatural function N\mathcal{N} stands separately as it represents phenomena that are neither controlled by the environment nor the scheduler but exist outside the formal model. This classification is informative; it explains which component determines the symbol's interpretation inside any structure.

Satisfaction & Models

The satisfaction judgment uses linear-time temporal logic with past over trace positions equipped with τ\tau. Definition schemata Fcomp!F_{\texttt{comp}!}, FcompF_{\texttt{comp}}, and FcomplinF^{\texttt{lin}}_{\texttt{comp}} are macros over this signature.

Let Tsch(a,b,tlag)T_{\textsf{sch}}(a,b,t_{\texttt{lag}}) denote the set of Scheduler Axioms: S1–S4 and L1–L3 with every modality instantiated using the same witnesses (a,b,tlag)(a,b,t_{\texttt{lag}}). Let TenvT_{\textsf{env}} denote the Environment Axioms EA1–EA7.

We write

E,S,N,τφ\langle \mathcal{E}, \mathcal{S}, \mathcal{N}, \tau \rangle \models \varphi

to mean that the structure interpreting environment-owned symbols via E\mathcal{E}, scheduler-owned symbols via S\mathcal{S}, the supernatural function via N\mathcal{N}, and the timestamp map via τ\tau satisfies the temporal formula φ\varphi in the standard LTL-with-past semantics. Here, EEnv\mathcal{E} \in \text{Env} is an individual environment, SSch\mathcal{S} \in \text{Sch} is an individual scheduler behavior, and NSupernatural\mathcal{N} \in \text{Supernatural} is the supernatural function mapping time to phenomenon types.

Models of the Theory

A trace over ΣenvΣschΣsupernatural\Sigma_{\textsf{env}} \cup \Sigma_{\textsf{sch}} \cup \Sigma_{\textsf{supernatural}} with timestamps τ\tau yields a structure E,S,N,τ\langle \mathcal{E}, \mathcal{S}, \mathcal{N}, \tau \rangle. The structure is a model of the theory, written as E,S,N,τT\langle \mathcal{E}, \mathcal{S}, \mathcal{N}, \tau \rangle \models T, iff:

  1. Environment-owned predicates are interpreted exactly as the lifts provided by the environment tuple E\mathcal{E} (which includes Compute\texttt{Compute}, Crash\texttt{Crash}, Due\texttt{Due}, RetryDue\texttt{RetryDue}, REs\texttt{REs}, REf\texttt{REf}, SS\texttt{SS}, and ISR\texttt{IS}_R).
  2. Scheduler-owned predicates are produced by the scheduler behavior S\mathcal{S} (at most one observable action per position, cf. EA3).
  3. The supernatural function is interpreted via N\mathcal{N}, mapping each time instant to the set of supernatural phenomenon types occurring at that instant.
  4. The structure satisfies every axiom in TenvTsch(a,b,tlag)T_{\textsf{env}} \cup T_{\textsf{sch}}(a,b,t_{\texttt{lag}}).

This perspective separates scheduler obligations from environmental truths (see Environment Axioms) and supernatural phenomena, anchoring liveness reasoning in the satisfaction relation defined above.

Conformance

This section is much less formal than the previous ones. Requirements in this section can be trivially gamed by filling in values adversarially for any of the parameters. Therefore, its main purpose is to give just a little bit more than a fully hand-wavy explanation of what conformance means. It culminates in something that can be summarized as "a scheduler implementation may do anything it wants in presence of things outside of our idealistic scheduler theory".

Implementations

A scheduler implementation is a function

I:Env×Supernatural×(NT)Sch\boxed{\mathcal{I} : \text{Env} \times \text{Supernatural} \times (\mathbb{N} \to \mathbb{T}) \to \text{Sch}}

that maps each triple of environment E\mathcal{E}, supernatural function N\mathcal{N}, and timestamp function τ\tau to a scheduler behavior S\mathcal{S}. Here, Env\text{Env} denotes the space of all possible environments (each providing Compute\texttt{Compute}, Crash\texttt{Crash}, Duex\texttt{Due}_x, RetryDuex\texttt{RetryDue}_x, REsx\texttt{REs}_x, REfx\texttt{REf}_x, SS\texttt{SS}, and ISR\texttt{IS}_R), Supernatural\text{Supernatural} denotes the space of all possible supernatural functions (each mapping TP(S)\mathbb{T} \to \mathcal{P}(\mathbb{S})), and Sch\text{Sch} denotes the space of all possible scheduler behaviors (producing IER\texttt{IE}_R, SE\texttt{SE}, and RSx\texttt{RS}_x events).

The implementation I\mathcal{I} is the abstract representation of the scheduler's code: given any environment, supernatural function, and timestamp function, it determines how the scheduler will respond. The timestamp function provides the temporal context for the scheduler's decisions. However, note that causality works both ways: the environment influences the scheduler's behavior, and the scheduler's actions affect the environment (e.g., by initiating callbacks).

World Theory

The world theory TworldT_{\mathrm{world}} is a theory that can reason about supernatural phenomena. Unlike TenvT_{\mathrm{env}} and TschT_{\mathrm{sch}}, which are formulated purely in terms of the observable scheduler/environment interface and cannot reference the supernatural function N\mathcal{N}, the world theory has N\mathcal{N} in its signature and can make assertions about it.

This theory captures the reader's background understanding that certain combinations of observables and supernaturals are coherent or incoherent. For example, TworldT_{\mathrm{world}} might assert that if a cosmic ray is reported at time tt (a supernatural phenomenon), then certain memory corruption patterns become plausible—connections that our formal scheduler theory cannot express because it doesn't "see" supernaturals.

We assume TenvTworldT_{\mathrm{env}} \subseteq T_{\mathrm{world}} because TenvT_{\mathrm{env}} consists of axioms that hold for all real-world environments (as stated in Environment), so these are also basic truths about the world.

The theory TworldT_{\mathrm{world}} itself is not explicitly axiomatized in this specification; it remains a parameter representing the reader's background knowledge about what constitutes a coherent world.

Important: TworldT_{\mathrm{world}} is not a theory of the actual physical world—it is an idealistic world theory. For instance, the world represented by the theory must be infinite. An infinite theory ensures that conformance cannot be achieved by enumerating and special-casing a finite set of world axioms, forcing implementations to be genuinely correct across all coherent traces.

Happy Set

A happy set H\mathcal{H} is a set of supernatural functions chosen by the user to represent the scenarios under which the scheduler is expected to operate correctly. The happy set captures the user's judgment about which combinations of supernatural phenomena are "reasonable" or "within scope" for the scheduler to handle.

The choice of happy set is not part of this specification—it is a parameter determined by the user's requirements, risk tolerance, and deployment context.

A structure M=E,S,N,τ\mathcal{M} = \langle \mathcal{E}, \mathcal{S}, \mathcal{N}, \tau \rangle is a happy trace (with respect to H\mathcal{H}) iff NH\mathcal{N} \in \mathcal{H}.

Conformance

Let T(a,b,tlag):=TenvTsch(a,b,tlag)T(a, b, t_{\mathrm{lag}}) := T_{\mathrm{env}} \cup T_{\mathrm{sch}}(a,b,t_{\mathrm{lag}}).

An implementation I\mathcal{I} is conformant with respect to a happy set H\mathcal{H} iff:

 happy trace M(I).  (M(I)Tworld)((a,b,tlag)  M(I)T(a,b,tlag))\boxed{ \forall \text{ happy trace } \mathcal{M}(\mathcal{I}).\; \big(\mathcal{M}(\mathcal{I}) \models T_{\mathrm{world}}\big) \Rightarrow \big(\exists (a, b, t_{\mathrm{lag}}) \; \mathcal{M}(\mathcal{I}) \models T(a, b, t_{\mathrm{lag}})\big) }

In other words, a conformant implementation must produce correct behavior for all happy traces. Specifically:

  • For every happy trace,
  • If the trace satisfies the world theory (is coherent with respect to TworldT_{\mathrm{world}}),
  • Then there must exist complexity witnesses (a,b,tlag)(a, b, t_{\mathrm{lag}}) such that the trace satisfies the combined scheduler and environment theory TT.

Traces that are not happy (supernatural function outside H\mathcal{H}) are considered out-of-scope, the scheduler is allowed to behave arbitrarily on them.

Interpretation: A conformant scheduler implementation behaves correctly on all traces that are both happy and coherent (satisfy the world theory). On traces that are either unhappy or incoherent, the scheduler may behave arbitrarily.