# Component convergence receipts — request

**Owner-visible evidence first:** after an injected late deployment failure, durable receipts name the
exact commit already running for each completed component. Retrying that same commit keeps those
components' process IDs unchanged, resumes unfinished work, and finishes without repeating completed
activation.

**Goal:** stop treating one late global failure as proof that every earlier component is stale. Preserve
the global deployment stamp as the whole-run/request high-water mark, but make component work and
restart decisions from independently committed convergence facts.

## Scope

- Add one shared receipt seam under the Overdeck state directory. Each receipt is atomically published
  JSON containing schema, component name, exact full target SHA, and publication time.
- Resolve each component's comparison base from the newest valid ancestor among its receipt and the
  rollout-compatible global success stamp. Missing, malformed, unknown, non-ancestor, or future
  receipts fail closed to an older valid base or force work.
- Publish a component receipt only after that component's install/activation and health contract has
  succeeded:
  - dependency tree after a complete/verified pnpm state;
  - Actions Gateway after its authenticated readiness check when enabled;
  - Kanboard after its installer/canary contract;
  - collector, web, controller, botmaster proxy, and web watchdog after atomic web activation plus the
    typed all-service readiness pass;
  - reaper notifier only when its installed running instance is proven.
- Drive existing dependency and service change gates from their component base rather than only the
  global stamp. No new service activation mechanism or backend artifact layout belongs in this slice;
  those are the next immutable-release slice.
- Keep global stamp publication and queue acknowledgement at the existing final durable-success seam.

## Contracts

1. A receipt means “this component was proved converged at this exact landed commit,” never merely
   built, copied, attempted, or restarted.
2. Receipt publication is one temp-file + rename operation in the receipt directory. A partial write is
   never readable as success.
3. The selected base must be a known commit and an ancestor of the current target. Ambiguity causes
   work, never a stale-code skip.
4. A failed component does not advance its receipt. Components proved before a later unrelated failure
   retain their receipts and can be kept on retry when their inputs and runtime health are unchanged.
5. A full successful global stamp remains authoritative rollout evidence and may advance a missing or
   older component receipt base. Existing installs therefore fail closed without migration downtime.
6. Queue durability, target identity, retry classification, rollback, and typed readiness contracts are
   unchanged.

## Acceptance

- Unit fixtures cover atomic valid receipts, malformed/torn receipts, unknown/non-ancestor targets,
  and newest-valid-ancestor selection against the global stamp.
- Deployment failure injection proves receipts publish only after their component success boundary.
- A retry after a late injected failure uses those receipts, does not repeat completed component
  restart work, and still retries the unfinished terminal work.
- Existing deploy behavior, idle-work, queue durability, retry, typed readiness, and shell static checks
  remain green.
- Land, install, and capture exact receipt contents plus before/after process evidence from the installed
  entrypoint before beginning immutable backend releases.

## Local evidence

- `packaging/tests/component-receipts.test.sh`: `component-receipts: all checks passed`.
- `packaging/test-deploy-local.sh`: `PASS=50 FAIL=0`; the injected late failure leaves eight exact-SHA
  receipts but no global success stamp, then the same-target retry performs one dependency install total
  and keeps all five core service PIDs unchanged.
- Focused deployment contracts are green: idle-work, collector restart gate, queue acknowledgement, and
  typed readiness.
- Warning-level ShellCheck is clean for the receipt implementation, deployment fixture, and changed
  collector receipt contract; all changed files pass `git diff --check`.

## Installed evidence

Revision `6c302b194977d23b576f30482f4bbb9d78bc94bd` is on `origin/main` and installed. A
controlled proof withheld only the global success stamp, pinned the retry to that exact revision, and
ran the installed deploy entrypoint twice. The first pass bootstrapped receipts through the normal typed
readiness boundary; the receipt-backed retry then reported:

```text
receipt_count=7
retry_pids_unchanged=yes
retry_dependency_install=skipped
retry_restarted=none
overdeck-collector.service=3929526
overdeck-web.service=3929537
overdeck-controller.service=3930445
botmaster-proxy.service=3929516
overdeck-web-watchdog.service=3929550
```

All seven installed receipts name the exact revision: dependencies, Kanboard, collector, web,
controller, botmaster proxy, and web watchdog. `reaper-notifier.service` was inactive, so the deploy
correctly did not publish a receipt claiming a running instance. Each forced proof pass atomically
restored the exact global stamp through the normal success finalizer; no backup stamp remains.
