Scheduling Agents with a Cadence Contract, Not a Bigger Cron Table
A recurring agent job is easy to start and surprisingly hard to operate: the schedule fires, but the work may duplicate, drift, or finish without a useful receipt. DAL can make cadence dependable by treating each scheduled run as a contract with a window, an idempotency key, and a verified output.
This article is a feature deep-dive into a concrete improvement for DAL scheduling: a cadence-aware run contract that separates “should run now” from “has already produced the promised result.” It explains the problem, the mechanism, and when builders should use it instead of ordinary time-based triggers.
The problem is not knowing the time
A cron expression can answer one question: when should a process wake up? It cannot, by itself, answer whether the previous run completed, whether its output is still valid, or whether a delayed process should execute twice to catch up.
Those distinctions matter for agent work. A daily article job may be delayed by a server restart. An integration check may take longer than its interval. A notification job may be retried after a timeout even though the first request succeeded. If the scheduler stores only timestamps, the runtime has to infer state from logs, filenames, or external systems—and inference is where duplicate work begins.
The safer abstraction is a cadence contract. Each occurrence has a stable identity, an allowed execution window, a declared output, and a completion receipt. Time decides when the occurrence becomes eligible; evidence decides whether it is done.
The cadence contract has four pieces
A useful contract can remain small:
- 1. Slot identity. A deterministic key such as
article_daily:2026-08-07identifies the intended occurrence. Retries reuse the key rather than creating a new commitment. - 2. Eligibility window. The slot has a scheduled time plus a tolerance window. A late worker can still claim the slot without pretending it ran at the original time.
- 3. Output promise. The job declares what it must produce: for example, one markdown file under
COO-FILESYSTEM/articles/drafts/. - 4. Receipt. Completion records the actual output path, verification result, and finishing time. A slot is complete only after the promised output is confirmed.
In pseudocode, the decision is deliberately boring:
```text slot = cadence.slot(job_id, calendar_period)
if receipt.exists(slot): return already_complete(receipt)
if now < slot.eligible_at: return not_due
if now > slot.expires_at: return expired_for_review
claim(slot) run(job) verify(output_promise) write_receipt(slot, output, verified=true) ```
The important step is not run(job). It is the distinction between claiming a slot and proving that it completed. A worker can fail after claiming; a retry can inspect the claim and the evidence before deciding whether to resume, recover, or surface the item for review.
Why stable slots beat timestamp comparisons
Many schedulers represent due work as “run every six hours.” That is adequate for stateless maintenance, but agent jobs often produce durable artifacts or external effects. For those jobs, a period-specific identity is more useful than a relative interval.
Suppose a three-times-daily status workflow is delayed by two hours. An interval-only scheduler may run immediately and then calculate the next run from the delayed time, slowly shifting the cadence. A slot-based scheduler keeps the intended boundaries and marks the late occurrence as late. It can also enforce a policy: run the missed slot once, skip it, or ask for review. That decision is explicit rather than an accidental consequence of process timing.
Stable slots also make retries safe. If an HTTP request times out, the scheduler can retry status:2026-08-07T12:00Z, not create status:retry-2. The resulting work log, artifact name, and receipt all point to one commitment. Operators can inspect one item instead of reconstructing a chain of guesses.
Verification belongs inside the scheduling mechanism
A scheduled task that returns successfully is not necessarily complete. The model may have produced text but failed to write the requested file. A script may have received a response but not persisted it. An API may have accepted a request whose downstream effect remains unknown.
Cadence-aware scheduling makes verification part of the contract. For filesystem output, verification can confirm that the path exists, is non-empty, and matches the expected type. For a draft-only article, that is enough to mark the slot complete. For an external message, verification should be stricter: record the destination, transport response, and any approval requirement. A timeout should remain unknown or blocked, not become a false success.
This arrangement keeps the scheduler honest about what it controls. It can guarantee that a draft file was created and checked. It cannot claim that a human approved publication unless the approval is represented by a separate event. The receipt should preserve that boundary.
When to use cadence contracts
Use this feature when a job has at least one of three properties: it creates a durable artifact, it may be retried, or its timing has operational meaning. Daily content drafts, periodic reports, synchronization passes, and review digests are good candidates.
A simple timer is still appropriate for disposable work: refreshing an in-memory cache, emitting a best-effort heartbeat, or running a local cleanup where repetition is harmless. Adding durable slot state to every tiny action would create needless operational weight.
The strongest use case is a job with a safe internal phase and a gated external phase. An article slot can generate and verify a draft automatically while leaving publication for a later approved transition. A travel workflow can refresh prices within a research slot while keeping booking as a separate, explicitly authorized commitment. Cadence governs preparation; effect gates govern consequences.
A practical DAL implementation path
Builders can introduce the mechanism without replacing the existing scheduler. Begin by deriving a slot key in the job runner from the job identifier and the intended calendar boundary. Store a small receipt beside the job’s durable logs or in the scheduler’s persistent state. Before execution, check the receipt and output path. After execution, verify the output and write the receipt atomically.
Next, add explicit outcomes: not_due, claimed, completed, blocked, and expired_for_review. These states are more useful than a single success flag because they tell the operator whether to wait, retry, inspect, or approve. Keep the inspection surface read-only and show one recommended next step for blocked or expired slots.
Finally, add a recovery rule for claims without receipts. The rule might allow a retry after a lease expires, but it should not silently overwrite an existing artifact or repeat an external effect. Recovery should inspect evidence first and escalate uncertainty when evidence cannot establish what happened.
Conclusion: make repetition accountable
Cadence is more than a clock. For agent systems, it is a sequence of commitments that must remain identifiable across delays, retries, restarts, and review gates. A cadence contract gives each occurrence a stable identity, a bounded opportunity to run, a concrete output promise, and a receipt proving completion.
The next practical steps are to define slot keys for one recurring DAL job, record verified outputs, and test delayed and retried execution before expanding the pattern. Keep scheduling responsible for eligibility and deduplication; keep review gates responsible for external effects. That division produces automation that can move on time—and stop cleanly when the evidence is not there.