# Controller-neutral SD qualification and independent A/B execution

Disposition: abandoned by owner; unfinished completion gates are not passed

Status: active; Gate 1 campaigns terminal and role-neutral runtime deployed; releasable baseline and physical qualification remain
Type: workpackage
Updated: 2026-09-23
Next Action: none; retained as history; any new execution requires a new explicit owner instruction
Campaign Reason: Historical record from campaign 009-complete-clean-contract-bound-a-b-qualification; retained independently after campaign closure and requires no separate owner-queue execution.
Campaign: standalone
Project Map: work/maps/map-smi-firmware-stabilization-and-qualification.md
Parent: work/checklists/checklist-sd-card-supply-change-project-closeout.md
Canonical Truth: docs/sd-card-qualification-contract.md and `jong@srv-rpi00.local:~/dev/sd_qualification/docs/`
Coordination: coordinated
Execution Route: work2

## Outcome

The SD Qualifier runs one immutable controller-neutral test definition
independently for Controller A and Controller B. Each role has its own runnable
frontier, durable task state, endpoint, probe identity, authorization, and
cross-operation J-Link lease. A and B may execute concurrently; neither role's
progress or completion authorizes the other. The UI sends only high-level
durable commands and may be refreshed or compatibly redeployed without
changing or interrupting the frozen backend test execution.

## Current limiting condition

Commit `8cdfa3bdc591ce29ac00a5411432239586b776e4` is deployed and removes the
matrix, readiness, scheduler, runner, and UI coupling. The host target-access
wrapper already provides the required cross-operation `flock` lease per role;
tests prove same-role serialization while the distinct A/B locks and J-Link
endpoints permit parallel execution.

The SD Qualifier recovery matrix, HPT power client, evidence binder, and
post-cycle adjudicator are now role-neutral. The host service explicitly maps
both `SDQ_CONTROLLER_A_RECOVERY_RUNNER` and
`SDQ_CONTROLLER_B_RECOVERY_RUNNER` to the same installed runner. Controller B
binds port `19121`, J-Link `69660123`, and the existing local HPT coordinated-
cycle API. A non-hardware B dispatch fixture and the full `428/428` application
suite pass. The remaining recovery gate is one explicitly authorized physical
B recovery run; `recovery_supported: false` correctly remains fail-closed
until physical qualification and the other live-profile gates are complete.

The Aug. 10 campaign is terminally closed `ABORTED` as the application's
supported INCONCLUSIVE administrative disposition, with no card rejection and
no qualification conclusion. A frozen read-only cross-campaign audit confirms
that the historical fragments cannot be assembled into a successful family
qualification: 13 target-bundle matrix leaves, all five A recovery cases, and
both regression rows are mechanically complete but remain review-only; 23
missing target matrix leaves have passes only under older firmware and are
rejected; 6 matrix leaves are absent everywhere; and B recovery, both required
workload-based endurance results, final scrubs/CID closeout, and reviewer outcomes are missing.
Both A and B supervisors remain healthy. The Aug. 10 campaign and all nine
remaining stale/superseded or fixture campaigns are now terminal `ABORTED`
with preserved evidence, unchanged sample results, and no qualification
conclusion. The database has zero non-terminal campaigns and zero active
execution operations. None of the closed campaigns may be resumed or
relabeled; the next campaign must start from the accepted contract-bound
release baseline.

## Governing architecture

```text
Versioned qualification contract
            |
     role-neutral test plan
       /                \
 A execution lane   B execution lane
 A shared lease     B shared lease
 port 19120         port 19121
 J-Link 69664082    J-Link 69660123
       \                /
 durable events, evidence, status API
            |
        operator UI
```

Controller-specific data is limited to role, assembly/hardware identity,
probe/endpoint, card/CID, power channel, authorization, and evidence
attribution. Test meaning, progress semantics, budgets, evaluation rules, and
result schema are shared.

## Work2 boundary

Authorized:

- plan and implement source changes in a dedicated Pi worktree;
- add schema/migrations, fixtures, tests, docs, and deployment configuration;
- run focused and adjacent automated tests;
- create a local source commit;
- deploy the candidate to the configured `srv-rpi00` work environment;
- verify health, migrations, restart/no-replay behavior, concurrent fixtures,
  and the authenticated web workflow; and
- create the post-deployment local checkpoint required by `work2`.

Not authorized by this route:

- reopen, relabel, or advance the closed Aug. 10 campaign;
- publish a new Start/Stop or perform controller/media writes;
- program firmware, cycle controller power, or run destructive media tests;
- migrate old campaign evidence into the new execution model; or
- push, release, or promote outside the configured work environment.

## Delivery stages

| Stage | Outcome | Entry evidence | Exit evidence |
| --- | --- | --- | --- |
| 1. Freeze execution contract | One catalog describes test ID, inputs, prerequisites, progress, budget, terminal outcomes, evidence, and replay policy independently of controller role | `SMI-SDQ-CONTRACT-V1`, current plan templates, HPT2 matrix and adapter contracts | Schema and expansion tests prove A/B definitions differ only in allowed controller bindings |
| 2. Generalize readiness and capabilities | Readiness and recovery are evaluated by role; shared-isolation checks do not depend on A progress | Protected A/B registry, distinct probes/endpoints, existing B policy history | A and B independently pass/fail readiness fixtures; missing capability blocks only its role |
| 3. Add independent scheduler lanes | One campaign can queue eligible A and B leaves concurrently with separate durable frontiers | Versioned plan and current coordinator/task model | Concurrent fixture proves two role tasks can be claimed and completed independently; pause/restart remains durable |
| 4. Unify per-role resource leases | Every programmer, observer, HPT command, initialization, scrub, recovery, and power action serializes on its role only | Current operation constraints and protected endpoint registry | Same-role overlap fails closed; A/B overlap succeeds; stale lease reconciles without replay |
| 5. Stabilize UI/backend boundary | UI uses versioned high-level command/status surfaces and cannot change frozen test meaning | Existing durable controls and event-sequence polling | Compatibility, refresh, reconnect, web restart, and web-only deployment tests pass while worker execution continues |
| 6. Deploy and verify work environment | Exact candidate operates on srv-rpi00 without changing the protected campaign | Stages 1–5, backup/rollback identity, clean candidate commit | Migrations, health, focused tests, concurrent non-controller fixtures, restart/no-replay, and authenticated browser checks pass |

## Implementation requirements

### Controller-neutral contract

- [x] Make each plan action bind exactly one `controller_role`; remove the A/B
  pair from role-local matrix payloads.
- [x] Validate that A/B expanded leaves use the same test ID, budget,
  prerequisites, progress, evaluation, and evidence policy.
- [x] Freeze contract and plan revision identities in each new campaign.
- [x] Preserve final cross-variant gates without using them as execution
  prerequisites.

### Independent execution lanes

- [x] Represent durable per-role frontier/state without duplicating campaigns.
- [x] Queue every currently eligible idle role instead of one global frontier.
- [x] Let A or B pause, block, fail, recover, or complete without changing the
  other lane unless a recorded shared-system/safety fault applies.
- [x] Derive campaign status from both lanes plus genuine global/reviewer gates.
- [x] Preserve idempotency, expired-lease reconciliation, and no command replay.

### Controller infrastructure

- [x] Replace B-specific admission with role-neutral readiness plus one
  deployment-level isolation proof for distinct probes, endpoints, and locks.
- [x] Add the same protected coordinated-cycle capability for B that A uses;
  route it by role and power channel.
- [ ] Qualify the complete Controller B recovery path with one explicitly
  authorized physical coordinated-cycle run and exact CID/evidence checks.
- [x] Use the appliance host's cross-operation role lease acquired by every
  Compose-routed J-Link consumer before target access.
- [x] Prove A uses `69664082`/`19120`, B uses `69660123`/`19121`, and neither can
  acquire or attribute the other's resource/evidence.

### UI/API boundary

- [x] Limit browser commands to high-level Run, Pause, Resume, and
  reviewer/disposition actions.
- [x] Expose both lane states, current nodes, progress, blockers, and events
  through a versioned read API or event-sequence stream.
- [x] Ensure browser input cannot provide endpoints, J-Link scripts, memory
  addresses, raw commands, or evidence interpretations.
- [x] Add compatibility tests proving a web-only update does not interrupt
  workers or change a frozen campaign definition.

## Focused verification matrix

| Scenario | Required result |
| --- | --- |
| Expand the same test for A and B | Definitions match except role-bound identity and infrastructure fields |
| Claim eligible A and B leaves | Both tasks become active without waiting for the other role |
| Two A J-Link consumers overlap | Second consumer fails closed on A lease |
| One A and one B consumer overlap | Both proceed with separate leases/endpoints |
| A lane blocks or fails | B lane continues unless a recorded shared fault applies |
| B lane blocks or fails | A lane continues unless a recorded shared fault applies |
| Coordinator/worker restart | Durable lane/task state resumes with no duplicate command or evidence |
| Web refresh/restart/update | Test execution continues; UI reconstructs status from durable events |
| Wrong probe/endpoint/CID | Only the affected role blocks before target mutation |
| Closed Aug. 10 campaign | Identifiers, coordinator/run state, and command history remain unchanged by later verification |

## Deployment protections

Before deployment:

- capture exact candidate commit/image identity and a verified database backup;
- record the protected campaign/coordinator/run state and latest command IDs;
- ensure verification fixtures have no live controller endpoints or authority;
- retain the current image/config as the rollback reference.

After deployment:

- verify web, database, coordinator, command, watchdog, and notification health;
- compare protected campaign and run identities/state to the baseline;
- prove no controller command/evidence event was added by deployment tests;
- run authenticated browser checks for dual-lane status and high-level controls;
- roll back if migration, health, compatibility, or paused-state invariants fail.

## Milestones

### Milestone 1: controller-neutral contract

- [x] Shared definition/schema and A/B parity fixtures pass.
- [x] Role-local actions contain only their assigned role.

### Milestone 2: independent backend execution

- [x] Dual-lane scheduler and unified per-role leases pass concurrent fixtures.
- [x] All B-only orchestration special cases are removed or generalized.

### Milestone 3: independent UI contract

- [x] Versioned command/status compatibility and web-continuity tests pass.
- [x] Browser exposes no raw controller surface.

### Milestone 4: work2 deployment

- [x] Candidate is locally committed and deployed to the work environment.
- [x] Focused backend and browser checks pass.
- [x] The then-paused live campaign execution state was unchanged and no controller operation occurred.
- [x] Post-deployment local checkpoints are recorded (`c6b53dc`, `8cdfa3b`).

## Completion standard

The requested `work2` core endpoint is deployed. This workpackage becomes
complete when the controller-neutral contract, independent A/B scheduler
lanes, unified
per-controller leases, role-neutral readiness/recovery, and compatible UI/API
boundary are implemented; focused and concurrency tests pass; the candidate is
deployed and browser-verified on `srv-rpi00`; exact rollback evidence is
recorded; and the campaign under protection remained unchanged with no
controller action. The Controller B recovery implementation is deployed and configured;
its physical end-to-end qualification and full physical A/B qualification
remain before closeout. Push and broader promotion remain separate later
routes.

## Related artifacts

- `docs/sd-card-qualification-contract.md`
- `docs/hpt2-live-command-adapter-v1.md`
- `work/adr/adr-controller-b-parallel-qualification-entry-policy.md`
- `work/checklists/checklist-sd-card-supply-change-project-closeout.md`
- `work/wp/active/wp-build-standalone-pi-sd-qualification-operator-application.md`

## Closeout routing

- Current truth promoted to: `docs/sd-card-qualification-contract.md` and Pi application docs
- Historical context remains in: this workpackage and the existing Controller B entry ADR
- Runtime/status evidence: a small dated manifest under `work/evidence/`
- Cleanup deferred to: stale-campaign disposition, reviewed evidence
  migration, and physical A/B qualification

## Owner-directed reconciliation — 2026-09-23

Owner withdrew the legacy standalone controller-neutral A/B qualification programme; the current MAP-0009 release matrix remains required.

Authorization: Owner instruction in this conversation on 2026-09-23 to close/abandon the named work and mitigate older active records.

Previous header retained for evidence interpretation:

> Status: active; Gate 1 campaigns terminal and role-neutral runtime deployed; releasable baseline and physical qualification remain
> Next Action: consolidate and admit one release line, integrate `SMI-SDQ-CONTRACT-V1`, register a contract-complete `CARD_FAMILY_INITIAL` plan, then review the 20 exact-target migration candidates before any physical execution

Earlier observations, unchecked historical criteria, and procedures below/above remain history. This administrative disposition does not qualify a new firmware candidate, physical card, thermal system, ECO, or release. Current 00.05.01 obligations in IDEA-0006, IDEA-0007, MAP-0009, and CAMP-0028 remain unchanged.
