Skip to content

Type to search pages.

View .md

The journal

Antifailure writes down what it is about to create before it creates it, and what it has removed after it removes it. That record is the journal, and it is what makes “nothing outlives an environment” a property rather than a hope.

intend container web ──> create it ──> confirm
intend network inner ──> create it ──> confirm
intend branch env-pr-41 ──> create it ──> confirm

The order matters. A process killed between intending and creating leaves a record of something that may or may not exist, and teardown can check. A process killed after creating and before recording would leave a resource nobody knows about, which is the leak this ordering prevents.

af down walks the journal, removes each resource, and confirms each removal against the provider. It does not trust the record: a resource the journal knows about and the provider does not is fine, and a resource the provider has and the journal does not is reported.

AF-RUN-030 The environment could not be torn down completely; 2 resources are
still recorded.
Next: Run 'af down' again once the provider is reachable; the journal
remembers what is left.

Running it again is safe and is the answer. Teardown is idempotent by construction: removing something already gone succeeds, in every provider, because the conformance suite has a behaviour that requires it.

Terminal window
af env list # what exists, read from the daemon
af env prune --older-than 0s # list all of it; nothing is removed
af env prune --older-than 0s --yes # remove exactly what that listed

The check that matters compares what the provider holds against what the journal recorded. Anything the provider has and the journal does not is something that escaped, and that is the failure the whole design exists to catch. The conformance suite runs it after every provider’s suite, and it has caught a provider leaking a golden per refresh.

AF-RUN-003 Another Antifailure process holds the lock for this branch (process
4821, since 12:04).
Next: Wait for it to finish, or stop it and run 'af down' to clean up.

One environment per branch per machine. Two runs would race on the same names and both fail in ways neither explains. The lock names the process and when it took it, so a stale one is recognisable.

AF-RUN-011 The local state database at ~/.antifailure/state.db is corrupt.
Next: A backup was written to ~/.antifailure/state.db.bak. The database was
rebuilt, so it now tracks nothing: run 'af env list' to see what is still
running and 'af env prune --older-than 0s --yes' to remove all of it.

The old file is kept rather than deleted, and the reconcile is the important half: a rebuilt journal knows about nothing, so anything still running is now untracked. af env list reads the daemon rather than the journal, which is what makes it the right tool here, and af env prune --older-than 0s lists what it finds, and removes it with --yes. That is the one situation where reading the provider matters more than reading the record.

.antifailure/ in the repository, next to the manifest. Per repository rather than per user, because the lock that stops two af up runs racing on one branch lives here, and a directory shared between checkouts would put two repositories’ environments in one lock namespace. af doctor prints the path it is using.

It is local state and belongs in .gitignore, which af init adds. It holds no secrets: connection strings are resolved when needed and never written down.

Related: the local runtime, providers.