# SD qualifier audited campaign closeout deployment — 2026-08-12

Status: complete
Type: evidence
Updated: 2026-08-12
Next Action: none; use the audited Overview action for reviewed idle stale campaigns
Parent: work/tickets/ticket-add-audited-campaign-closeout-to-sd-qualifier.md

## Delivered result

The deployed campaign Overview now has an explicit `Close campaign` action.
It requires a reason and confirmation, records an append-only
`campaign.closed` event with actor and prior state, sets the existing terminal
`ABORTED` disposition and completion time, preserves all evidence, and presents
the result to operators as `CLOSED — without qualification conclusion` in
History. The former reasonless generic `RUNNING -> ABORTED` transition was
removed.

Closeout fails closed while a campaign has an open run or a running/pausing or
claimed coordinator task. An idle waiting/blocked coordinator is placed in the
paused desired state during the same locked transaction. No schema migration,
firmware change, controller action, or physical-media operation was required.

## Source and image identity

- Pi source worktree: `~/dev/sdq-closeout-20260812`
- Local-only branch: `codex/campaign-closeout-20260812`
- Commit: `520014c4673e7e14de6c051a90d1153c7fc4a0e6`
- Commit subject: `Add audited campaign closeout`
- Push: not performed
- Release: `campaign-closeout-520014c`
- ARM64 image: `sha256:1edb079d8fc1295713b08f4642032b49e11dd5cab608f49e8a8943d3cd6c3c7a`

## Focused validation

The exact ARM64 image reported no model changes and passed 40 focused tests:

- new campaign-closeout service and UI tests;
- adjacent campaign workflow tests;
- persistent coordinator tests;
- responsive CSS tests.

These cases cover successful audited closeout, required reason/confirmation,
open-run refusal, active-coordinator refusal, idle blocked-coordinator pause,
History classification, and adjacent workflow behavior.

Authenticated Playwright against `http://srv-rpi00.local/sd-qualifier/`
verified:

- the Overview exposes `Close campaign` for the Aug. 10 campaign and an idle
  coordinator fixture;
- the form posts to the campaign-specific `/close/` endpoint;
- reason and confirmation are browser-required;
- the 390-pixel mobile page has no document-level horizontal overflow;
- the fixture campaign event request returns HTTP 200;
- the current page has zero console errors.

No production campaign was closed as part of validation. The exact-image tests
exercise the successful mutation path without adding another live fixture
campaign to the operator dashboard.

## Deployment verification

Only `sd-qualifier-web-1` was recreated. It is healthy and reports release
`campaign-closeout-520014c` and source commit `520014c...a0e6`. The internal
health endpoint reports `status=ok`, database/storage/clock/workers true, and
`required_now_ready=true`.

The command worker, campaign coordinator, notification worker, and
qualification watchdog retained the same container IDs and start times across
deployment. The current Aug. 10 campaign retained raw state `RUNNING`, version
`2`, and update timestamp `2026-08-11T20:16:39.449498+00:00`; no closeout was
submitted against it.
