Defect A - shared guard deletion and first-creation race:
- The shared V2 guard is now a persistent coordination object. It is never
deleted after creation; release and rollback are both a compare-and-swap
back to the exact unclaimed sentinel (0.0), so a contender that acquires
the guard between an owner's CAS and its cleanup keeps its claim.
- First creation is fenced by ballots: the contender announces its own
ballot, scans for live foreign ballots, re-reads the guard AFTER the scan
(a stale observation of absence is never used), verifies the sentinel it
wrote, claims it by CAS and re-scans afterwards. A rival found at any
point fails the claim closed and the guard is given back with a CAS to
the sentinel - never deleted, never overwritten.
- The owner's ballot stays visible for as long as it owns the guard and is
renewed by the heartbeat; only a contender's own ballot is ever removed,
and only after it no longer owns the guard.
- UQ_GUARD_UNCLAIMED is a distinct protocol state, accepted for the V2
guard namespace only. The legacy guard namespace keeps zero as corrupt
evidence, and negative, fractional, non-finite and future values stay
invalid everywhere.
- Ownership loss is latched for the lifetime of the guard object.
Defect B - ownership loss must stop persistence:
- CUQInstanceGuard implements CUQOwnershipVerifier: a read-only proof that
the guard still carries this instance's value and is still inside the TTL.
- CUQRisk binds that verifier after the guard is acquired and before Init(),
and refuses to initialize without one.
- A persistence boundary inside CUQRisk gates the primary write, the backup
write, the staging write, legacy migration, V2 marker creation, marker
restoration, marker removal and reservation reconciliation. Any failure
latches the loss: the controller is unhealthy, entries are blocked, and
no retry or reacquisition is possible in that instance.
- UQStateSave() takes the verifier and fences its three file mutations
individually, so a loss proven before the primary commit cannot write it.
EA event ordering:
- OnTick() and OnTimer() verify ownership before risk evaluation, lock
servicing, trailing and symbol processing.
- OnTradeTransaction() does not invoke persistence-capable reservation
reconciliation after the loss.
- OnDeinit() releases only a guard this instance provably still holds.
- Heartbeats are throttled; every event performs the read-only proof, so a
two second timer is not the only discovery path.
Input semantics:
- InpPreventDuplicateInstances is deprecated and reserved. Exclusive
persistence ownership is unconditional, and an ownership loss always
blocks entries, so the input has no effect. It is kept so existing .set
files keep loading, and a runtime note reports that it is ignored.
Preserved unchanged: V2 fingerprint and file locators, legacy identity hash
and key, legacy ambiguity refusal, risk limits and strategy logic.