Background Agents

Every lesson in this course builds one system: a stablecoin reserve attestation registry that discovers issuers, reads the PDFs they publish, and refuses to publish a field it could not read. What it is and where this lesson sits.

Tier
3 Pro
Build position
19
Throughlines
D Execution surface · H Isolation and parallel safety · C Delegation topology
Verdict
existing practice
Commit
eeadad0
Demo
scripts/terms/demo-17.ts
Runs in
the course repository

A scheduled job with a model in it. The scheduling is ordinary — cron has existed for forty years — and saying so is the honest start.

What changes is that nobody is watching. Term 18 removed the human from a run; this removes them from the decision to start one, and that adds three failure modes attended work does not have.

Overlap. The previous run has not finished when the next one fires. Two agents, same job, same paths, which is interstitial II happening on a timer.

Drift. A run fails and the next starts from the failed state, compounding rather than retrying.

Silence. A run fails and nothing says so, because the thing that would have noticed is the person who is not there.

The interesting design is not the schedule. It is what the job does when it is wrong and nobody is looking.

The mechanism

admit() decides before any work happens, and the order of its checks is the design:

  1. Halted first, because a job that stopped itself must not be restarted by a schedule. Only a person clears it.
  2. Overlap next, because a second concurrent run is worse than a missed one.
  3. The write gate last, and still pre-flight. A job that discovers mid-run that it may not write has already done something.

settle() counts consecutive failures. Three in a row halt the job. A retry that never gives up is not resilience — it is a loop producing the same wrong answer at a regular interval, and the streak converts an unattended failure into a stopped job, which is a state a human eventually notices.

The receipt

artifacts/17-scheduled.json, twelve firings:

 run  outcome   streak  reason
   1  ok             0  completed
   2  skipped        0  previous run has not finished; overlapping the same job
   3  ok             0  completed
   4  ok             0  completed
   5  failed         0  the job returned a non-zero exit
   6  failed         1  the job returned a non-zero exit
   7  failed         2  the job returned a non-zero exit
   8  refused        3  halted after 3 consecutive failures; a person must clear it
  ...
ok 3, failed 3, skipped 1, refused 5
halted after run 7

a job trying to write outside its directory: refused — worktree-containment

Failures and overlaps are supplied rather than sampled, so the timeline is identical on every machine. A simulation of unattended flakiness that is itself flaky teaches nothing.

The timeline that tested nothing

The first version put the failures at runs 4–6 and the overlap at run 9. The job halted at run 6, so the overlap was never reached — that entire path went untested while the demo printed a tidy table and exited zero.

The overlap has to happen while the job is still alive. The demo asserts a skip occurred, which is what caught it.

Break it first

mutation                                     tests                 demo
overlapping runs allowed                     2 failed | 11 passed  exit 1
the job never halts itself                   2 failed | 11 passed  exit 1
streak counts cumulative, not consecutive    2 failed | 11 passed  exit 0

The third is the subtle one. Counting cumulative failures instead of consecutive ones halts every long-lived job eventually, no matter how healthy — a job failing once a fortnight stops after six weeks. The test that catches it alternates failures and asserts the job never halts.

Where it overlaps

Line D is execution surface, and this is the rung past headless: not merely unattended during a run, but unattended in deciding to run. Term 18 is the substrate; term 28 is where this stops being a habit and becomes a pipeline. Line F is determinism wrapping stochasticity — the admission gate is the deterministic part, and it is the only part that will still behave when nobody is watching. Line H is isolation, because an overlapping job is a fan-out nobody chose.

A personal teaching project, in development. The registry it builds is a teaching artifact and is not an assurance opinion about any issuer. Not affiliated with or endorsed by any employer, or by any vendor whose tools it describes. Where a unit depends on a specific flag or path, it names the version it was verified against. All units.