# SD Qualifier Aug. 10 campaign inconclusive closeout

Status: complete
Type: evidence
Updated: 2026-08-13
Next Action: none; continue the ordered project closeout queue at Gate 1 stale-campaign disposition
Parent: work/checklists/checklist-sd-card-supply-change-project-closeout.md
Canonical Truth: the live `srv-rpi00.local` SD Qualifier database, immutable evidence ledger, and deployed image

## Outcome

Campaign `8c7a2b1a-7e67-48ac-8895-7999d76c4c2a` is terminally closed
without a qualification conclusion and without rejecting either physical card.
The application represents that operator-facing `INCONCLUSIVE` decision with
its supported terminal state and final disposition `ABORTED`; the permanent
reason explicitly states `INCONCLUSIVE`, the contract and bundle-admission
conflicts, incomplete Controller B S2 and S4-S6 coverage, no card rejection,
and no controller resume.

The coordinator and both lanes remain `PAUSED`. All runs and HPT2 operations
remain terminal. No Start, Stop, firmware, power, media, or card-disposition
operation was issued. A post-close manifest and report record the terminal
state, completion time, disposition, reason, and `qualification_conclusion:
false`.

## Rollback point and transition

Immediately before closeout, the documented Compose services created and
restore-checked:

- `/backups/sd-qualifier-20260813T235028Z.dump`;
- size `3,984,857` bytes;
- SHA-256 `010411a0f6cd9865d3a2aba0fb1b3c12e89990e0ee275f843d8887e108a6c24a`;
- disposable PostgreSQL restore check: passed with `11` campaigns.

The application closeout service revalidated exact campaign ID, version `2`,
state `RUNNING`, paused coordinator and lanes, zero active runs, zero unresolved
HPT2 operations, and zero pending/claimed coordinator tasks. It then recorded:

- campaign state/final disposition: `ABORTED / ABORTED`;
- campaign version: `3`;
- completed at: `2026-08-13T23:52:09.385028Z`;
- event: `campaign.closed`, sequence `1691`, actor `admin`;
- event qualification conclusion: `false`;
- coordinator state/desired state: `PAUSED / PAUSED`, version `65`.

## Non-replay and card preservation

Before and after closeout:

- all `187` runs remained terminal: `180 COMPLETED`, `4 ABORTED`, `3 BLOCKED`;
- HPT2 operation count remained `361`: `359 ACKNOWLEDGED`, `1 BLOCKED`,
  `1 REJECTED`;
- unresolved HPT2 operation count remained `0`;
- selected operation-record digest remained
  `ef19080154f4b2d39ecfee4db45cd89ee0d106a92936e1a92a839aaf5f0cd186`;
- both assignments remained `PENDING`, with no disposition actor, time,
  reason, or failure attribution;
- selected assignment-record digest remained
  `6852e471275733518f7ecdfbb4be30248c1fd5d6dda27d4dc4208122b3ca701c`.

## Report reconciliation

The report format now preserves campaign `completed_at`,
`final_disposition`, `disposition_reason`, and whether a qualification
conclusion exists. The deployed authenticated report endpoint published event
`report.published` at sequence `1692`, actor `admin`, with exactly two new
immutable evidence rows and no HPT2-operation change:

| Evidence | ID | Bytes | SHA-256 |
| --- | ---: | ---: | --- |
| campaign manifest | `19655` | `4,413,308` | `3550156c2be56c7f23bfe474b976db0e4d68c421d69d904bc030d088bc777c60` |
| qualification report | `19656` | `1,354` | `7094cace3965450b86c6725aeeaf7cfbf89ec9885d67a1d18ebb55b343358aa3` |

Both files match their recorded size and SHA-256. The manifest records
`state=ABORTED`, `final_disposition=ABORTED`, the exact `INCONCLUSIVE` reason,
and `qualification_conclusion=false`; the rendered report presents the same
facts.

## Closeout UI and deployment

The first live post-close inspection exposed misleading resume controls and a
live supervisor warning on the terminal detail page. The server already
rejected coordinator resume for terminal campaigns. Focused source change
`6fcb7df2aeed6d28a7955f0399d598ebf8c432a4` removed terminal campaign
controls and suppressed live supervisor warnings for terminal history.
Source change `470d62b484fd81903ac2269071d96d42794a6add` added the report closeout
fields.

- exact ARM64 image:
  `srv-rpi00-sd-qualifier:terminal-closeout-470d62b`;
- image digest:
  `sha256:cdbd11314f3496887a9699f7a541b8b9e313d7ef43aea4fcf43d8b039ed0155c`;
- focused closeout/report tests: `9 / 9` passed on the exact image;
- preceding campaign closeout plus adjacent view suite: `57 / 57` passed;
- web and qualification-watchdog containers are healthy;
- PostgreSQL, command-worker, campaign-coordinator, and notification-worker
  identities were preserved across the final configuration deployment.

Authenticated Playwright verified the exact campaign only in History as
`CLOSED — Closed without qualification conclusion`, the permanent
`INCONCLUSIVE` reason, no resume/reconcile controls, no live supervisor alert,
the new manifest/report at the top of Results, and zero page-console errors.

## Observer retirement

The host observer was still bound to a run in the closed campaign and was
adding read-only status observations after terminal disposition. The exact
`sdq-qualification-observer.service` was disabled and stopped, its final
orphaned one-off observer container was stopped and removed, and no tagged
J-Link firewall rule remained. Observation evidence stayed fixed at count
`10,941`, maximum ID `19658`, across a later poll interval.

A host-local Compose override removes `qualification-host-observer` from the
web and watchdog required-worker lists while no exact campaign observer is
installed. Health remains `status=ok`, `required_now_ready=true`, and
`workers=true`. Before any clean campaign begins controller execution, its
reviewed exact run/role observer must be installed and the normal required
worker set restored.

## Final state

- campaign: `ABORTED`, version `3`, closed without qualification conclusion;
- coordinator/desired state: `PAUSED / PAUSED`;
- active runs / operations / tasks: `0 / 0 / 0`;
- HPT2 operations: `361`, unchanged;
- campaign events: contiguous through sequence `1692`;
- card dispositions: unchanged and not rejected;
- host observer: disabled and inactive;
- live application health: OK.

No successor campaign was created. Gate 2 must first provide one reviewed,
contract-bound release baseline; a clean campaign must install its own exact
observer binding before controller execution.
