# Rust unattached initiator writer ownership

## Reproduced baseline

The unchanged initiator at `013eafa7381df2df5f4517cc72bacb8fd4a85c43`
runs the same eleven-case public-API fixture as the candidate. Three controls
pass: an ordinary refused dial releases once, successful attachment retains
the primary, and an observer panic after attachment retains it with the session.
Eight regressions fail:

- Connecting observer panic before a socket exists.
- Connected observer panic before attachment.
- A promoted store's sequence-recovery getter panicking.
- Reconnect's clock hook panicking before attachment.
- TCP and proxy deadline overflow.
- TLS-handshaking observer panic before TLS takes the socket.
- A real HA file-store writer retained across Connecting observer panic.

The seven public memory-backed lease cases observe the old owner still primary
and its standby unable to promote. They save that observation and clean the
baseline owner before asserting. Socket cleanup already works through the
earlier dial guard; this reproduction concerns writer ownership. The fixture
bytes are identical before and after the fix. The baseline reports 3 passed,
8 failed, 0 ignored, Cargo exit 101 and no TLS resource skip.

The pro-only HA case uses a unique empty journal under the session build root.
A separate test process confirms Standby while the original writer holds its
real file-store fences. After the observer panic, another process attempts
promotion and still gets Standby on the baseline. The parent records this
original result, releases its baseline writer and then asserts. Child output
is captured; its failure is one observation within the parent case, rather
than another fixture in the eleven-case count. Parent and child use the same
compiled binary and store dimensions. Fixture directories are deleted on drop.
This is a local synthetic journal test, separate from the previously retained
two-host shared-store proof and from any authorized customer pilot.

## Ownership boundary

`DialPrimary` borrows the initiator after `try_become_primary` returns Held or
Promoted. Its guard spans promotion recovery, Connecting/Connected/TLS observers,
deadline/proxy setup and reconnect's pre-attachment clock hook. If that path
unwinds, the acquired writer is released through the store's existing
`release_primary` method. The inner dial guards close unattached transport
resources before the writer guard releases its owner.

The private `connect_primary` helper keeps the remaining dial flow together
without raw pointers or unsafe aliasing. Ordinary resolution/dial failures
disarm the fallback before their existing explicit release, preserving release
before endpoint rotation and avoiding a second release if that explicit backend
call itself panics. Successful reconnect disarms the fallback immediately after
socket ownership transfers. The attached session keeps its writer fence through
later callbacks; ordinary Logon refusal and explicit teardown retain their
existing release paths.

There is no public API/enum change, session destructor, new allocation or
per-message work. Lifecycle publication, reconnect counters and panic propagation
retain their contracts. Cleanup relies on each backend's `release_primary`
contract; a cleanup panic during an existing unwind has Rust's double-panic
behavior. This slice makes no latency or production qualification claim.

## Verification and retention

| Gate | Result |
|---|---|
| Unchanged engine with identical fixture | 3 controls passed, 8 regressions failed |
| Focused default/open writer ownership cases | 11 / 10 passed, no TLS resource skip |
| Real HA file-store external-process contender | Passed in the default edition |
| Complete default Rust stage | 2,097 passed, 0 failed, 1 existing ignored builders doctest |
| Complete open Rust stage | 1,908 passed, 0 failed, the same 1 ignored doctest |
| Strict all-target Clippy, `-D warnings` | Passed in both editions |
| New fixture rustfmt, export scan, API inventory and coverage | Passed |

Final complete gates use `25f341fd3da456c43ab2349fd4d7ca94c27ecff6`,
including upstream `CheckLatency` / `MaxLatency` and the local-clock SendingTime
check. All 368 tracked Rust and 632 shared fixture/reference/gate/consumer
input path-keysets and SHA256 hashes match before and after qualification.
Each selected Rust stage reports 1 ran, 0 failed, 0 skipped and PARTIAL for the
other unselected monorepo stages. Focused TLS cases have no resource skip;
the successful external-process HA probes are part of the default fixture.

The preceding `d826af874` candidate passes 2,094 / 1,905 full cases and strict
Clippy in both editions before the latency changes arrive. Those results are
retained separately; complete tests and strict Clippy repeat for the integrated
pin. The fixture remains byte-identical to the negative baseline throughout.
An initial read-only evidence-copy command used the remote home as its working
directory and failed before copying or changing source; repeating it from the
owned worktree establishes the actual baseline pin and matching source snapshot.

Tests use Rust/Cargo 1.92.0 and strict Clippy the retained 1.93.1 sysroot.
Heavy jobs run serially on Scan, isolated CPUs 10–19, at `-j8` with one test
thread. The physical-host guard requires more than 120 GiB total and at least
64 GiB available, limits observed foreign process RSS to 16 GiB and refuses
foreign compilers whose affinity overlaps its pool. Queued waits are retained.
BEELINK2 and HP run no heavy job for this slice.

Retained source pins and baseline snapshots, identical fixture proof, commands,
negative baseline, actual external-process results, full reports/stdout/stderr,
Clippy logs, resource guard and recoverable candidate/publication bundle live
under `~/archive/libhft/rust-initiator-primary-ownership-20261012`.

API/session/subsystem scores stay unchanged. Live production feed/order endpoint
evidence and venue/FIXP certification remain open; the existing two-host HA/C2
and physical NIC records retain their scope. The integrated pin includes SendingTime configuration alignment. The proposed
missing/malformed SendingTime contract remains unruled.
