Status
Accepted. Amended by 0016: each environment and scope now has its own branch,sponson-receipts/<env>/<scope>; sponson/receipts is read only as a fallback for scopes not yet migrated.
Context
Drift detection, destroy and resuming a partial apply all need to know what the previous run did. The recommended place to runapply is CI, where every job starts on a clean machine, so a receipt kept in the working directory is
gone by the next run.
Options considered:
Decision
Receipts are written through an interface,ReceiptStore (packages/core/src/types.ts): read, write, list,
and the lock operations acquireLock, renewLock, readLock, releaseLock. Two implementations ship:
git-branch(default): an orphan branchsponson/receiptsin the user’s repository, on theoriginremote. CI already has a token that can push to it (contents: write), so no new credential is needed.local:.sponson/receipts/, used when there is no remote and by tests.
packages/core/src/receipts/layout.ts): <environment>/<scope>/latest.json, one
<runId>.json per run, and lock.json. Each run adds a file, so concurrent scopes never conflict on content, only on
the ref. The git store treats a rejected non-fast-forward push as a failed compare-and-swap: fetch, re-check, retry
with jittered backoff within a time budget (SPONSON_STORE_BUDGET_MS, default 60 s). When the budget runs out it
reports STORE_CONTENDED; when the server keeps refusing the push it keeps a copy under .sponson/unpushed/ and
reports STORE_REJECTED.
Consequences
- A CI run sees what the previous run did without any service outside the repository.
- The receipts branch history is a record of every run. Because receipts hold only keyed hashes and non-sensitive outputs (ADR 0009), the branch is safe to keep.
- A hosted store is a third implementation of the same interface; nothing in the engine changes.
- Every store operation is a fetch and a push, which is slow under contention. The lease’s renewal paces itself so a slow store cannot queue renewals (ADR 0008).
- Deleting the branch makes Sponson forget what it manages:
planthen reports Sponson’s resources as unmanaged rather than failing.