//! core_test — exercises the lease engine's reliability properties (Part 3).
//! These are the priority-#1 guarantees in code: leases bound to liveness,
//! atomic grant, the claim lattice, ghost-free ownership across client death.
//!
//! These tests use `Deadline.none` because the FakeBackend is instantaneous
//! and the contract-under-deadline is exercised separately in
//! `conformance.zig` (the "S2: slow op yields Timeout" test).

const std = @import("std");
const testing = std.testing;
const model = @import("mgf_hrb_model");
const kabi = @import("mgf_hrb_kabi");
const cap = @import("mgf_hrb_cap");
const FakeBackend = @import("mgf_hrb_fake_backend").FakeBackend;
const coremod = @import("mgf_hrb_core");
const Core = coremod.Core;

const Urn = model.Urn;
const Err = model.Err;
const D = kabi.Deadline;

fn seeded(fb: *FakeBackend) !kabi.KernelBackend {
    try fb.add("hw:/pci/0000:01:00.0/fn0", .claimable, .pcie_function);
    try fb.add("hw:/usb/bus1/dev4/if0", .claimable, .usb_interface);
    return fb.backend();
}

test "core: a claim creates a live lease and marks the resource claimed" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    var core = Core.init(testing.allocator, try seeded(&fb));
    defer core.deinit();
    const urn = Urn.from("hw:/pci/0000:01:00.0/fn0");

    const id = try core.claim(&urn, .exclusive, 42, D.none);
    try testing.expect(id != 0);
    try testing.expectEqual(@as(usize, 1), core.liveLeaseCount());
    const st = core.stateOf(&urn);
    try testing.expect(st == .claimed);
    try testing.expectEqual(@as(model.ClientId, 42), st.claimed.owner);
}

test "core lattice: exclusive conflicts with an existing exclusive (Part 3.3)" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    var core = Core.init(testing.allocator, try seeded(&fb));
    defer core.deinit();
    const urn = Urn.from("hw:/pci/0000:01:00.0/fn0");

    const id = try core.claim(&urn, .exclusive, 1, D.none);
    try testing.expectError(Err.Conflict, core.claim(&urn, .exclusive, 2, D.none));
    // the failed claim left no residue
    try testing.expectEqual(@as(usize, 1), core.liveLeaseCount());
    try core.release(id, 1, D.none);
}

test "core lattice: observe never conflicts; many observers coexist" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    var core = Core.init(testing.allocator, try seeded(&fb));
    defer core.deinit();
    const urn = Urn.from("hw:/usb/bus1/dev4/if0");

    const a = try core.claim(&urn, .observe, 1, D.none);
    const b = try core.claim(&urn, .observe, 2, D.none);
    const c = try core.claim(&urn, .observe, 3, D.none);
    try testing.expectEqual(@as(usize, 3), core.liveLeaseCount());
    try core.release(a, 1, D.none);
    try core.release(b, 2, D.none);
    try core.release(c, 3, D.none);
}

test "core lattice: observe coexists with exclusive (read while controlled)" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    var core = Core.init(testing.allocator, try seeded(&fb));
    defer core.deinit();
    const urn = Urn.from("hw:/pci/0000:01:00.0/fn0");

    const x = try core.claim(&urn, .exclusive, 1, D.none);
    const o = try core.claim(&urn, .observe, 2, D.none); // a monitor watches the controlled device
    try testing.expectEqual(@as(usize, 2), core.liveLeaseCount());
    try core.release(x, 1, D.none);
    try core.release(o, 2, D.none);
}

test "core G3: client death reclaims ALL its leases — ghost ownership impossible" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    var core = Core.init(testing.allocator, try seeded(&fb));
    defer core.deinit();
    const pci = Urn.from("hw:/pci/0000:01:00.0/fn0");
    const usb = Urn.from("hw:/usb/bus1/dev4/if0");

    // client 7 holds two devices, then "crashes"
    _ = try core.claim(&pci, .exclusive, 7, D.none);
    _ = try core.claim(&usb, .exclusive, 7, D.none);
    try testing.expectEqual(@as(usize, 2), core.liveLeaseCount());

    const reclaimed = core.holderDied(7);
    try testing.expectEqual(@as(usize, 2), reclaimed);
    try testing.expectEqual(@as(usize, 0), core.liveLeaseCount());

    // both resources are safe-reset and immediately re-claimable by someone else
    try testing.expect(fb.isSafe("hw:/pci/0000:01:00.0/fn0"));
    try testing.expect(fb.isSafe("hw:/usb/bus1/dev4/if0"));
    const reborn = try core.claim(&pci, .exclusive, 99, D.none);
    try core.release(reborn, 99, D.none);
}

test "core G3: one client's death does not touch another client's leases" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    var core = Core.init(testing.allocator, try seeded(&fb));
    defer core.deinit();
    const pci = Urn.from("hw:/pci/0000:01:00.0/fn0");
    const usb = Urn.from("hw:/usb/bus1/dev4/if0");

    const survivor = try core.claim(&pci, .exclusive, 1, D.none);
    _ = try core.claim(&usb, .exclusive, 2, D.none);

    const reclaimed = core.holderDied(2); // only client 2 dies
    try testing.expectEqual(@as(usize, 1), reclaimed);
    try testing.expectEqual(@as(usize, 1), core.liveLeaseCount()); // client 1 untouched
    try testing.expect(core.stateOf(&pci) == .claimed); // still held by 1
    try core.release(survivor, 1, D.none);
}

test "core atomicity: a failed hardware acquire leaves no lease (Part 3.4)" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    var core = Core.init(testing.allocator, try seeded(&fb));
    defer core.deinit();
    const urn = Urn.from("hw:/pci/0000:01:00.0/fn0");

    fb.fail_acquire = true; // force the hardware step (the LAST fallible step) to fail
    try testing.expectError(Err.HardwareFault, core.claim(&urn, .exclusive, 1, D.none));
    // errdefer must have unwound the reserved slot — zero leases, resource safe
    try testing.expectEqual(@as(usize, 0), core.liveLeaseCount());
    try testing.expect(fb.isSafe("hw:/pci/0000:01:00.0/fn0"));

    fb.fail_acquire = false;
    const ok = try core.claim(&urn, .exclusive, 1, D.none); // recovery: normal claim works
    try core.release(ok, 1, D.none);
}

test "core release: idempotent — releasing an unknown lease is a no-op" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    var core = Core.init(testing.allocator, try seeded(&fb));
    defer core.deinit();
    const urn = Urn.from("hw:/pci/0000:01:00.0/fn0");

    const id = try core.claim(&urn, .exclusive, 1, D.none);
    try core.release(id, 1, D.none);
    try core.release(id, 1, D.none); // double release — must be a safe no-op
    try core.release(99999, 1, D.none); // never-existed lease — also safe
    try testing.expectEqual(@as(usize, 0), core.liveLeaseCount());
}

test "core G1/G4: raw channel only for the lease holder, gone after release" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    var core = Core.init(testing.allocator, try seeded(&fb));
    defer core.deinit();
    const urn = Urn.from("hw:/pci/0000:01:00.0/fn0");

    const id = try core.claim(&urn, .exclusive, 5, D.none);
    _ = try core.raw(id, 5, D.none); // holder gets the direct channel
    try testing.expectError(Err.NotPermitted, core.raw(id, 6, D.none)); // non-holder refused
    try core.release(id, 5, D.none);
    try testing.expectError(Err.InvalidToken, core.raw(id, 5, D.none)); // gone after release
}

// === S2 — deadlines on the seam are honoured (D-029) =======================
//
// The fake's `slow_*_ms` toggles simulate a slow backend op. A claim whose
// deadline cannot cover the work returns `Err.Timeout`; no lease is committed;
// the resource is untouched (D-012 atomicity holds through the timeout path).

test "S2: a claim whose deadline can't cover the work returns Err.Timeout" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    var core = Core.init(testing.allocator, try seeded(&fb));
    defer core.deinit();
    const urn = Urn.from("hw:/pci/0000:01:00.0/fn0");

    fb.slow_acquire_ms = 5000; // backend declares 5 s of work
    const short = D.fromNow(50); // caller offers 50 ms
    try testing.expectError(Err.Timeout, core.claim(&urn, .exclusive, 1, short));

    // ATOMICITY UNDER TIMEOUT: no lease committed, resource safe at the
    // backend level. The Core then quarantines the URN (Part 2.7.1) —
    // the next claim sees Err.Unavailable until a verified reset
    // clears it. The atomicity property is unchanged; what's added is
    // the "we don't trust this device right now" record at the engine
    // level — the downward-boundary analog of how leases handle the
    // upward boundary.
    try testing.expectEqual(@as(usize, 0), core.liveLeaseCount());
    try testing.expect(fb.isSafe("hw:/pci/0000:01:00.0/fn0"));

    // Even with adequate budget, the next claim is refused — quarantined.
    fb.slow_acquire_ms = 0;
    try testing.expectError(
        Err.Unavailable,
        core.claim(&urn, .exclusive, 1, D.fromNow(1000)),
    );

    // A verified clean reset clears the quarantine; claim works again.
    _ = core.clearQuarantine(&urn);
    const ok = try core.claim(&urn, .exclusive, 1, D.fromNow(1000));
    try core.release(ok, 1, D.none);
}

test "Part 2.7.1: quarantineStatus reports the reason after a timeout" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    var core = Core.init(testing.allocator, try seeded(&fb));
    defer core.deinit();
    const urn = Urn.from("hw:/pci/0000:01:00.0/fn0");

    try testing.expect(core.quarantineStatus(&urn) == null); // initially clear

    fb.slow_acquire_ms = 5000;
    _ = core.claim(&urn, .exclusive, 1, D.fromNow(50)) catch {};

    const q = core.quarantineStatus(&urn) orelse return error.UnexpectedNull;
    try testing.expectEqual(@import("mgf_hrb_model").QuarantineReason.op_timeout, q.reason);
    try testing.expect(q.since_ms > 0);
}

test "Part 2.7.1: clearQuarantine on an unknown URN is a no-op" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    var core = Core.init(testing.allocator, try seeded(&fb));
    defer core.deinit();
    const urn = Urn.from("hw:/pci/0000:01:00.0/fn0");
    try testing.expect(core.clearQuarantine(&urn) == false);
}

test "S2: a generous deadline lets the same slow op succeed" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    var core = Core.init(testing.allocator, try seeded(&fb));
    defer core.deinit();
    const urn = Urn.from("hw:/pci/0000:01:00.0/fn0");

    fb.slow_acquire_ms = 50; // backend declares 50 ms of work
    const ok = try core.claim(&urn, .exclusive, 1, D.fromNow(5000)); // 5 s budget
    try core.release(ok, 1, D.none);
}

test "S2: Deadline.none never expires even against a backend declaring slow work" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    var core = Core.init(testing.allocator, try seeded(&fb));
    defer core.deinit();
    const urn = Urn.from("hw:/pci/0000:01:00.0/fn0");

    fb.slow_acquire_ms = 1000; // declared slow
    // none means "I have no deadline; just do the work" — for boot enumeration
    // and similar paths where waiting indefinitely is genuinely desired.
    const ok = try core.claim(&urn, .exclusive, 1, D.none);
    try core.release(ok, 1, D.none);
}

// === FEEDBACK SDK-03 — Core.listLeases ====================================
//
// The lease engine is the authoritative source of "who holds what." These
// tests pin the read-side projection a GUI consumes via Client.list_leases:
// scope filtering, mode preservation, holder preservation, grant ordering,
// and the empty-table case.

const LeaseRecord = @import("mgf_hrb_core").LeaseRecord;
const LeaseSink = @import("mgf_hrb_core").LeaseSink;

const RecordCollector = struct {
    records: std.ArrayListUnmanaged(LeaseRecord) = .empty,
    alloc: std.mem.Allocator,

    fn push(ctx: *anyopaque, r: LeaseRecord) void {
        const self: *RecordCollector = @ptrCast(@alignCast(ctx));
        self.records.append(self.alloc, r) catch {};
    }
    fn sink(self: *RecordCollector) LeaseSink {
        return .{ .ctx = self, .push = push };
    }
    fn deinit(self: *RecordCollector) void {
        self.records.deinit(self.alloc);
    }
};

test "SDK-03 listLeases: empty table yields zero records" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    var core = Core.init(testing.allocator, try seeded(&fb));
    defer core.deinit();

    var col = RecordCollector{ .alloc = testing.allocator };
    defer col.deinit();
    const s = col.sink();
    core.listLeases("hw:/**", &s);
    try testing.expectEqual(@as(usize, 0), col.records.items.len);
}

test "SDK-03 listLeases: one held lease appears with urn / mode / holder preserved" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    var core = Core.init(testing.allocator, try seeded(&fb));
    defer core.deinit();
    const urn = Urn.from("hw:/pci/0000:01:00.0/fn0");

    const id = try core.claim(&urn, .exclusive, 42, D.none);
    defer core.release(id, 42, D.none) catch {};

    var col = RecordCollector{ .alloc = testing.allocator };
    defer col.deinit();
    const s = col.sink();
    core.listLeases("hw:/**", &s);

    try testing.expectEqual(@as(usize, 1), col.records.items.len);
    const r = col.records.items[0];
    try testing.expect(std.mem.eql(u8, r.urn.slice(), "hw:/pci/0000:01:00.0/fn0"));
    try testing.expectEqual(@as(model.LeaseId, id), r.lease_id);
    try testing.expectEqual(@as(model.ClientId, 42), r.holder);
    try testing.expectEqual(model.ClaimMode.exclusive, r.mode);
    // granted_at_ms is monotonic ms; on any sane host it's > 0 after the claim.
    try testing.expect(r.granted_at_ms > 0);
}

test "SDK-03 listLeases: scope filter narrows by URN glob (PCI-only)" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    var core = Core.init(testing.allocator, try seeded(&fb));
    defer core.deinit();
    const pci = Urn.from("hw:/pci/0000:01:00.0/fn0");
    const usb = Urn.from("hw:/usb/bus1/dev4/if0");

    const a = try core.claim(&pci, .exclusive, 1, D.none);
    const b = try core.claim(&usb, .observe, 2, D.none);
    defer core.release(a, 1, D.none) catch {};
    defer core.release(b, 2, D.none) catch {};

    var col = RecordCollector{ .alloc = testing.allocator };
    defer col.deinit();
    const s = col.sink();
    core.listLeases("hw:/pci/**", &s);

    try testing.expectEqual(@as(usize, 1), col.records.items.len);
    try testing.expectEqual(@as(model.LeaseId, a), col.records.items[0].lease_id);
}

test "SDK-03 listLeases: many observers on one URN all appear (lattice allows it)" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    var core = Core.init(testing.allocator, try seeded(&fb));
    defer core.deinit();
    const urn = Urn.from("hw:/usb/bus1/dev4/if0");

    const a = try core.claim(&urn, .observe, 1, D.none);
    const b = try core.claim(&urn, .observe, 2, D.none);
    const c = try core.claim(&urn, .observe, 3, D.none);

    var col = RecordCollector{ .alloc = testing.allocator };
    defer col.deinit();
    const s = col.sink();
    core.listLeases("hw:/**", &s);

    // Three observers, all distinct, all visible — the GUI lease pane
    // needs to show every concurrent observer (FEEDBACK SDK-03).
    try testing.expectEqual(@as(usize, 3), col.records.items.len);
    var seen_holders: [4]bool = .{ false, false, false, false };
    for (col.records.items) |r| {
        try testing.expectEqual(model.ClaimMode.observe, r.mode);
        seen_holders[r.holder] = true;
    }
    try testing.expect(seen_holders[1]);
    try testing.expect(seen_holders[2]);
    try testing.expect(seen_holders[3]);

    try core.release(a, 1, D.none);
    try core.release(b, 2, D.none);
    try core.release(c, 3, D.none);
}

test "SDK-03 listLeases: released lease disappears immediately" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    var core = Core.init(testing.allocator, try seeded(&fb));
    defer core.deinit();
    const urn = Urn.from("hw:/pci/0000:01:00.0/fn0");

    const id = try core.claim(&urn, .exclusive, 7, D.none);
    try core.release(id, 7, D.none);

    var col = RecordCollector{ .alloc = testing.allocator };
    defer col.deinit();
    const s = col.sink();
    core.listLeases("hw:/**", &s);
    try testing.expectEqual(@as(usize, 0), col.records.items.len);
}

test "SDK-03 listLeases: granted_at_ms is monotonic — later grants have later timestamps" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    var core = Core.init(testing.allocator, try seeded(&fb));
    defer core.deinit();

    const a = try core.claim(&Urn.from("hw:/pci/0000:01:00.0/fn0"), .exclusive, 1, D.none);
    // Force a measurable delta — kabi.nowMs() resolution is per-ms; sleep
    // a bit so the second claim demonstrably observes a later tick.
    const ts = std.os.linux.timespec{ .sec = 0, .nsec = 2_000_000 };
    _ = std.os.linux.nanosleep(&ts, null);
    const b = try core.claim(&Urn.from("hw:/usb/bus1/dev4/if0"), .exclusive, 2, D.none);

    var col = RecordCollector{ .alloc = testing.allocator };
    defer col.deinit();
    const s = col.sink();
    core.listLeases("hw:/**", &s);

    try testing.expectEqual(@as(usize, 2), col.records.items.len);
    // The two grants happened in order; the timestamps must reflect that.
    // (records.items are in lease-grant order — append-only with swapRemove
    // on release; we made no releases here.)
    try testing.expect(col.records.items[1].granted_at_ms >= col.records.items[0].granted_at_ms);

    try core.release(a, 1, D.none);
    try core.release(b, 2, D.none);
}

// === Part 7.1 multi-client concurrency — Core mutex correctness ============
//
// With the broker now spawning a thread per accepted client (server.zig
// thread-per-client refactor), multiple threads can hit the same Core
// concurrently. These tests pin the Core mutex's correctness properties:
// no double-grant on a contended URN, no lease-table corruption under
// concurrent claims on different URNs, no lost releases.

const ThreadCtx = struct {
    core: *Core,
    urn: Urn,
    holder: model.ClientId,
    result: ?model.Err = null,
    lease_id: model.LeaseId = 0,
};

fn claimWorker(ctx: *ThreadCtx) void {
    ctx.lease_id = ctx.core.claim(&ctx.urn, .exclusive, ctx.holder, D.none) catch |e| {
        ctx.result = e;
        return;
    };
}

test "concurrency: N threads claiming the SAME URN — exactly one wins" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    try fb.add("hw:/pci/0000:01:00.0/fn0", .claimable, .pcie_function);
    var core = Core.init(testing.allocator, fb.backend());
    defer core.deinit();

    const N: usize = 8;
    var ctxs: [N]ThreadCtx = undefined;
    var threads: [N]std.Thread = undefined;
    var i: usize = 0;
    while (i < N) : (i += 1) {
        ctxs[i] = .{
            .core = &core,
            .urn = Urn.from("hw:/pci/0000:01:00.0/fn0"),
            .holder = @intCast(i + 1),
        };
    }
    i = 0;
    while (i < N) : (i += 1) {
        threads[i] = try std.Thread.spawn(.{}, claimWorker, .{&ctxs[i]});
    }
    i = 0;
    while (i < N) : (i += 1) {
        threads[i].join();
    }
    // Exactly one thread should win; the rest should see Conflict.
    var winners: usize = 0;
    var conflicts: usize = 0;
    for (ctxs) |ctx| {
        if (ctx.result == null) {
            winners += 1;
        } else if (ctx.result.? == model.Err.Conflict) {
            conflicts += 1;
        }
    }
    try testing.expectEqual(@as(usize, 1), winners);
    try testing.expectEqual(N - 1, conflicts);
    try testing.expectEqual(@as(usize, 1), core.liveLeaseCount());
}

test "concurrency: N threads claiming DIFFERENT URNs — all succeed" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    const N: usize = 8;
    // Seed N distinct URNs.
    var urn_bufs: [N][128]u8 = undefined;
    var i: usize = 0;
    while (i < N) : (i += 1) {
        const s = std.fmt.bufPrint(&urn_bufs[i], "hw:/pci/0000:01:00.{d}/fn0", .{i}) catch unreachable;
        try fb.add(s, .claimable, .pcie_function);
    }
    var core = Core.init(testing.allocator, fb.backend());
    defer core.deinit();

    var ctxs: [N]ThreadCtx = undefined;
    var threads: [N]std.Thread = undefined;
    i = 0;
    while (i < N) : (i += 1) {
        const s = std.fmt.bufPrint(&urn_bufs[i], "hw:/pci/0000:01:00.{d}/fn0", .{i}) catch unreachable;
        ctxs[i] = .{
            .core = &core,
            .urn = Urn.from(s),
            .holder = @intCast(i + 1),
        };
    }
    i = 0;
    while (i < N) : (i += 1) {
        threads[i] = try std.Thread.spawn(.{}, claimWorker, .{&ctxs[i]});
    }
    i = 0;
    while (i < N) : (i += 1) {
        threads[i].join();
    }
    // Every claim should have succeeded — they're on independent URNs.
    var ok_count: usize = 0;
    for (ctxs) |ctx| {
        if (ctx.result == null) ok_count += 1;
    }
    try testing.expectEqual(N, ok_count);
    try testing.expectEqual(N, core.liveLeaseCount());

    // Cleanup: release each lease.
    for (ctxs) |ctx| {
        if (ctx.result == null) try core.release(ctx.lease_id, ctx.holder, D.none);
    }
}

test "concurrency: stress — interleaved claim+release across threads stays consistent" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    try fb.add("hw:/pci/0000:01:00.0/fn0", .claimable, .pcie_function);
    try fb.add("hw:/pci/0000:02:00.0/fn0", .claimable, .pcie_function);
    try fb.add("hw:/pci/0000:03:00.0/fn0", .claimable, .pcie_function);
    var core = Core.init(testing.allocator, fb.backend());
    defer core.deinit();

    const Worker = struct {
        fn run(c: *Core, urn_str: []const u8, holder: model.ClientId, iters: usize) void {
            var k: usize = 0;
            while (k < iters) : (k += 1) {
                const urn = Urn.from(urn_str);
                const id = c.claim(&urn, .exclusive, holder, D.none) catch |e| {
                    // Conflict expected when another thread holds it;
                    // anything else is a real bug.
                    if (e != model.Err.Conflict) {
                        std.debug.print("unexpected error: {s}\n", .{@errorName(e)});
                        return;
                    }
                    continue;
                };
                c.release(id, holder, D.none) catch {};
            }
        }
    };

    const ITERS: usize = 200;
    const t1 = try std.Thread.spawn(.{}, Worker.run, .{ &core, "hw:/pci/0000:01:00.0/fn0", @as(model.ClientId, 1), ITERS });
    const t2 = try std.Thread.spawn(.{}, Worker.run, .{ &core, "hw:/pci/0000:01:00.0/fn0", @as(model.ClientId, 2), ITERS });
    const t3 = try std.Thread.spawn(.{}, Worker.run, .{ &core, "hw:/pci/0000:02:00.0/fn0", @as(model.ClientId, 3), ITERS });
    const t4 = try std.Thread.spawn(.{}, Worker.run, .{ &core, "hw:/pci/0000:03:00.0/fn0", @as(model.ClientId, 4), ITERS });
    t1.join();
    t2.join();
    t3.join();
    t4.join();

    // After all churn settles, the table should be empty (every claim
    // either failed with Conflict or was followed by a release).
    try testing.expectEqual(@as(usize, 0), core.liveLeaseCount());
}

// =============================================================================
// A4 (Cluster J, ROADMAP R2) — Core.lock is dropped around
// backend.acquire. The under-lock phase reserves a placeholder
// lease (token.id=0); the slow acquire runs outside the lock;
// Phase 3 installs the real token. The tests below pin the
// observable BEHAVIOUR (the lattice continues to work, the
// rollback path leaves no residue).
//
// **Not pinned in Zig tests:** empirical lock-drop verification
// (a thread holding the lock for the duration of acquire) needs
// a backend that REALLY sleeps in vAcquire — FakeBackend's
// `slow_acquire_ms` only controls the deadline-budget check, not
// real-time slowness. A dedicated sleeping-backend test fixture
// is a separate piece of work; until then the lock-drop is
// covered by code review + the existing
// "N threads claiming SAME URN — exactly one wins" test (line 452
// above), which validates that no race produces double-grant
// even under the new lock-drop shape.
// =============================================================================

test "A4: rollback on acquire failure leaves no residue" {
    // When backend.acquire fails (Phase 2), the placeholder
    // from Phase 1 MUST be removed (Phase 2's catch block).
    // Pre-A4 there was no placeholder; post-A4 the rollback
    // must clean it up. Pin: a failed claim leaves
    // liveLeaseCount() at 0.
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    try fb.add("hw:/pci/0000:03:00.0/fn0", .claimable, .pcie_function);
    fb.fail_acquire = true;  // every acquire returns HardwareFault
    var core = Core.init(testing.allocator, fb.backend());
    defer core.deinit();

    const urn = Urn.from("hw:/pci/0000:03:00.0/fn0");
    try testing.expectError(model.Err.HardwareFault, core.claim(&urn, .exclusive, 1, D.none));
    // No placeholder residue from the failed claim.
    try testing.expectEqual(@as(usize, 0), core.liveLeaseCount());

    // A second claim against the same URN MUST succeed — the
    // failed claim's rollback left nothing in the compat-check
    // path that would conflict.
    fb.fail_acquire = false;
    const id = try core.claim(&urn, .exclusive, 2, D.none);
    try testing.expect(id > 0);
    try core.release(id, 2, D.none);
}

test "A4: rollback on quarantine-triggering Timeout leaves no lease residue" {
    // Phase 2 Timeout path: the URN transitions to quarantined
    // + the placeholder is removed. Pin: liveLeaseCount() at 0
    // AND the next claim returns Err.Unavailable (proves the
    // quarantine record was set, not just the placeholder
    // cleaned).
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    try fb.add("hw:/pci/0000:04:00.0/fn0", .claimable, .pcie_function);
    fb.slow_acquire_ms = 5000;  // declared work exceeds caller's deadline
    var core = Core.init(testing.allocator, fb.backend());
    defer core.deinit();

    const urn = Urn.from("hw:/pci/0000:04:00.0/fn0");
    const short = D.fromNow(10);  // caller offers 10ms; declared 5s
    try testing.expectError(model.Err.Timeout, core.claim(&urn, .exclusive, 1, short));
    try testing.expectEqual(@as(usize, 0), core.liveLeaseCount());
    // Next claim sees Err.Unavailable — quarantine in effect.
    fb.slow_acquire_ms = 0;
    try testing.expectError(
        model.Err.Unavailable,
        core.claim(&urn, .exclusive, 1, D.fromNow(1000)),
    );
}

// ---- S5 / Tier-1 #9: bounded everything (lease ceilings) ----------------

test "S5 #9: aggregate lease ceiling sheds new claims with Err.Overloaded" {
    // Observe-mode claims never conflict (the lattice permits unlimited
    // concurrent observers on one URN), so they're the cheapest way for a
    // flood to grow the ownership table. The aggregate per-Core ceiling
    // (MAX_LEASES) is the hard DoS bound: at the ceiling, a new claim is
    // shed with Err.Overloaded — back-pressure, never a crash, never
    // unbounded growth. Null-peer (in-process) claims are bounded by this
    // aggregate ceiling alone.
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    try fb.add("hw:/test/dev0", .claimable, .pcie_function);
    var core = Core.init(testing.allocator, fb.backend());
    defer core.deinit();

    const urn = Urn.from("hw:/test/dev0");
    var first_id: model.LeaseId = 0;
    var i: usize = 0;
    while (i < coremod.MAX_LEASES) : (i += 1) {
        const id = try core.claim(&urn, .observe, @intCast(i + 1), D.none);
        if (i == 0) first_id = id;
    }
    try testing.expectEqual(coremod.MAX_LEASES, core.liveLeaseCount());
    // At the ceiling: shed, don't grow.
    try testing.expectError(Err.Overloaded, core.claim(&urn, .observe, 99999, D.none));
    try testing.expectEqual(coremod.MAX_LEASES, core.liveLeaseCount());
    // Releasing one frees a slot — back-pressure is transient, not a wedge.
    try core.release(first_id, 1, D.none);
    const reborn = try core.claim(&urn, .observe, 88888, D.none);
    try testing.expect(reborn > 0);
}

test "S5 #9: per-tenant lease ceiling is keyed on the unforgeable peer uid" {
    // The per-tenant ceiling (MAX_LEASES_PER_UID) keys on the SO_PEERCRED
    // uid, NOT the client-supplied holder id. One tenant filling its quota
    // must NOT block a different tenant. An UNBOUND cap permits any peer
    // (cap_test pins this), so a single cap + distinct PeerCreds lets us
    // record distinct uids through the production claimWithCap
    // path while the cap check uniformly passes.
    var ct = cap.CapTable.init(testing.allocator);
    defer ct.deinit();
    const observe_cap = try ct.mint(.{
        .scope = Urn.from("hw:/**"),
        .rights = cap.RightSet.of(&.{.observe}),
    });

    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    try fb.add("hw:/test/dev0", .claimable, .pcie_function);
    var core = Core.initWithCaps(testing.allocator, fb.backend(), &ct);
    defer core.deinit();

    const urn = Urn.from("hw:/test/dev0");
    const alice = cap.PeerCred{ .uid = 1000, .pid = 100 };
    const bob = cap.PeerCred{ .uid = 1001, .pid = 200 };

    // Alice fills her per-tenant quota. The holder id varies every claim
    // (1, 2, 3, …) — proving the cap is NOT evadable by changing holder:
    // the uid is what counts.
    var i: usize = 0;
    while (i < coremod.MAX_LEASES_PER_UID) : (i += 1) {
        _ = try core.claimWithCap(observe_cap, alice, &urn, .observe, @intCast(i + 1), D.none);
    }
    // Alice is at her ceiling — even a fresh holder id is shed.
    try testing.expectError(
        Err.Overloaded,
        core.claimWithCap(observe_cap, alice, &urn, .observe, 99999, D.none),
    );
    // Bob (different uid) is unaffected: per-tenant, not aggregate. This
    // holds because MAX_LEASES_PER_UID < MAX_LEASES, so Alice's quota
    // doesn't exhaust the aggregate table.
    const bob_lease = try core.claimWithCap(observe_cap, bob, &urn, .observe, 1, D.none);
    try testing.expect(bob_lease > 0);
}

test "S5 #9: a tenant's leases are reclaimed, freeing its quota (holder death)" {
    // The per-tenant ceiling must be self-healing: when a tenant's holder
    // dies, its leases are reclaimed and its quota frees up. Pins that the
    // ceiling tracks LIVE leases, not a monotonic counter.
    var ct = cap.CapTable.init(testing.allocator);
    defer ct.deinit();
    const observe_cap = try ct.mint(.{
        .scope = Urn.from("hw:/**"),
        .rights = cap.RightSet.of(&.{.observe}),
    });

    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    try fb.add("hw:/test/dev0", .claimable, .pcie_function);
    var core = Core.initWithCaps(testing.allocator, fb.backend(), &ct);
    defer core.deinit();

    const urn = Urn.from("hw:/test/dev0");
    const alice = cap.PeerCred{ .uid = 1000, .pid = 100 };
    const holder: model.ClientId = 7;

    var i: usize = 0;
    while (i < coremod.MAX_LEASES_PER_UID) : (i += 1) {
        _ = try core.claimWithCap(observe_cap, alice, &urn, .observe, holder, D.none);
    }
    try testing.expectError(
        Err.Overloaded,
        core.claimWithCap(observe_cap, alice, &urn, .observe, holder, D.none),
    );
    // Alice's connection (holder 7) dies — every lease it held is reclaimed.
    _ = core.holderDied(holder);
    // Quota is free again: Alice can claim.
    const reborn = try core.claimWithCap(observe_cap, alice, &urn, .observe, holder, D.none);
    try testing.expect(reborn > 0);
}

// ---- Tier-1 #12: reset-escalation ladder (recoverByReset) ---------------

/// Quarantine a seeded URN by forcing an acquire timeout (the production
/// trigger), so the recovery tests start from a real quarantined state.
fn quarantineViaTimeout(core: *Core, fb: *FakeBackend, urn: *const Urn) !void {
    fb.slow_acquire_ms = 5000; // declared work exceeds the caller's deadline
    try testing.expectError(Err.Timeout, core.claim(urn, .exclusive, 1, D.fromNow(10)));
    fb.slow_acquire_ms = 0;
    // Sanity: it's quarantined (a fresh claim is refused).
    try testing.expectError(Err.Unavailable, core.claim(urn, .exclusive, 1, D.fromNow(1000)));
}

test "#12 ladder: FLR succeeds → recovered_flr, resource returns to Free" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    try fb.add("hw:/test/dev0", .claimable, .pcie_function);
    var core = Core.init(testing.allocator, fb.backend());
    defer core.deinit();

    const urn = Urn.from("hw:/test/dev0");
    try quarantineViaTimeout(&core, &fb, &urn);

    const outcome = core.recoverByReset(&urn, D.none);
    try testing.expectEqual(coremod.RecoveryOutcome.recovered_flr, outcome);
    // Recovered: the quarantine is cleared and the URN is claimable again.
    try testing.expect(core.quarantineStatus(&urn) == null);
    const id = try core.claim(&urn, .exclusive, 1, D.none);
    try testing.expect(id > 0);
}

test "#12 ladder: FLR fails → escalates to bus reset → recovered_bus" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    try fb.add("hw:/test/dev0", .claimable, .pcie_function);
    var core = Core.init(testing.allocator, fb.backend());
    defer core.deinit();

    const urn = Urn.from("hw:/test/dev0");
    try quarantineViaTimeout(&core, &fb, &urn);

    // The device ignores FLR but yields to a bus-level reset.
    fb.reset_fails_below = .bus_level;
    const outcome = core.recoverByReset(&urn, D.none);
    try testing.expectEqual(coremod.RecoveryOutcome.recovered_bus, outcome);
    try testing.expect(core.quarantineStatus(&urn) == null);
}

test "#12 ladder: both rungs fail → still_quarantined, reason escalated" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    try fb.add("hw:/test/dev0", .claimable, .pcie_function);
    var core = Core.init(testing.allocator, fb.backend());
    defer core.deinit();

    const urn = Urn.from("hw:/test/dev0");
    try quarantineViaTimeout(&core, &fb, &urn);

    // No reset level works — the device is stuck.
    fb.can_reset = false;
    const outcome = core.recoverByReset(&urn, D.none);
    try testing.expectEqual(coremod.RecoveryOutcome.still_quarantined, outcome);
    // Stays quarantined, with the reason escalated to reset_unverified
    // (FLR+bus were tried), and still not claimable.
    const q = core.quarantineStatus(&urn);
    try testing.expect(q != null);
    try testing.expectEqual(model.QuarantineReason.reset_unverified, q.?.reason);
    try testing.expectError(Err.Unavailable, core.claim(&urn, .exclusive, 1, D.fromNow(1000)));
}

test "#12 ladder: a non-quarantined resource is a no-op (never force-reset)" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    try fb.add("hw:/test/dev0", .claimable, .pcie_function);
    var core = Core.init(testing.allocator, fb.backend());
    defer core.deinit();

    const urn = Urn.from("hw:/test/dev0");
    // Healthy + claimed: recovery must NOT reset a device in service.
    const id = try core.claim(&urn, .exclusive, 1, D.none);
    try testing.expect(id > 0);
    try testing.expectEqual(coremod.RecoveryOutcome.not_quarantined, core.recoverByReset(&urn, D.none));
    // The lease is untouched (the device was never reset).
    try testing.expectEqual(@as(usize, 1), core.liveLeaseCount());
    try core.release(id, 1, D.none);
}

// ---- Tier-1 #8: recovery contract (integrity invariants + reconcile) ----

test "#8 invariants: a sound lease table passes" {
    const Lease = coremod.Lease;
    const a = Lease{ .id = 1, .urn = Urn.from("hw:/test/dev0"), .holder = 1, .mode = .exclusive, .token = .{ .id = 9 }, .granted_at_ms = 0 };
    // observe coexists with exclusive on the same URN — sound.
    const b = Lease{ .id = 2, .urn = Urn.from("hw:/test/dev0"), .holder = 2, .mode = .observe, .token = .{ .id = 8 }, .granted_at_ms = 0 };
    const c = Lease{ .id = 3, .urn = Urn.from("hw:/test/dev1"), .holder = 3, .mode = .exclusive, .token = .{ .id = 7 }, .granted_at_ms = 0 };
    const leases = [_]Lease{ a, b, c };
    try testing.expect(coremod.verifyLeaseInvariants(&leases) == null);
}

test "#8 invariants: a double-exclusive grant on one URN is caught" {
    const Lease = coremod.Lease;
    const a = Lease{ .id = 1, .urn = Urn.from("hw:/test/dev0"), .holder = 1, .mode = .exclusive, .token = .{ .id = 9 }, .granted_at_ms = 0 };
    const b = Lease{ .id = 2, .urn = Urn.from("hw:/test/dev0"), .holder = 2, .mode = .exclusive, .token = .{ .id = 8 }, .granted_at_ms = 0 };
    const leases = [_]Lease{ a, b };
    // The worst reliability lie — two exclusive leases on one resource.
    try testing.expectEqual(@as(?usize, 1), coremod.verifyLeaseInvariants(&leases));
}

test "#8 invariants: a zero holder / duplicate id is caught" {
    const Lease = coremod.Lease;
    const z = Lease{ .id = 1, .urn = Urn.from("hw:/test/dev0"), .holder = 0, .mode = .observe, .token = .{ .id = 9 }, .granted_at_ms = 0 };
    try testing.expectEqual(@as(?usize, 0), coremod.verifyLeaseInvariants(&[_]Lease{z}));
    const a = Lease{ .id = 5, .urn = Urn.from("hw:/test/dev0"), .holder = 1, .mode = .observe, .token = .{ .id = 9 }, .granted_at_ms = 0 };
    const dup = Lease{ .id = 5, .urn = Urn.from("hw:/test/dev1"), .holder = 2, .mode = .observe, .token = .{ .id = 8 }, .granted_at_ms = 0 };
    try testing.expectEqual(@as(?usize, 1), coremod.verifyLeaseInvariants(&[_]Lease{ a, dup }));
}

test "#8 audit: a normally-claimed core is sound (auditInvariants → null)" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    var core = Core.init(testing.allocator, try seeded(&fb));
    defer core.deinit();
    const pci = Urn.from("hw:/pci/0000:01:00.0/fn0");
    const usb = Urn.from("hw:/usb/bus1/dev4/if0");
    _ = try core.claim(&pci, .exclusive, 1, D.none);
    _ = try core.claim(&usb, .observe, 2, D.none);
    try testing.expect(core.auditInvariants() == null);
}

test "#8 reconcile: hardware-bound but unclaimed → quarantined (re-derivation)" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    try fb.add("hw:/test/dev0", .claimable, .pcie_function);
    try fb.add("hw:/test/dev1", .claimable, .pcie_function);
    try fb.add("hw:/test/dev2", .claimable, .pcie_function);
    var core = Core.init(testing.allocator, fb.backend());
    defer core.deinit();

    const dev0 = Urn.from("hw:/test/dev0");
    // dev0 is held by a live client; dev1 + dev2 are bound in hardware
    // but unclaimed (e.g. a worker restart lost their in-memory leases).
    _ = try core.claim(&dev0, .exclusive, 1, D.none);
    const bound = [_]Urn{ dev0, Urn.from("hw:/test/dev1"), Urn.from("hw:/test/dev2") };
    const n = core.reconcileAfterRestart(&bound);
    // The two unclaimed-but-bound resources are quarantined; the live one
    // is left alone (never assumed free, never assumed owned).
    try testing.expectEqual(@as(usize, 2), n);
    try testing.expect(core.quarantineStatus(&Urn.from("hw:/test/dev1")) != null);
    try testing.expect(core.quarantineStatus(&Urn.from("hw:/test/dev2")) != null);
    try testing.expect(core.quarantineStatus(&dev0) == null);
    // The quarantined ones aren't claimable until recovered; the live one
    // stays held.
    try testing.expectError(Err.Unavailable, core.claim(&Urn.from("hw:/test/dev1"), .exclusive, 9, D.fromNow(1000)));
    // Idempotent: a second reconcile quarantines nothing new.
    try testing.expectEqual(@as(usize, 0), core.reconcileAfterRestart(&bound));
}

test "#8 fuzz: random claim/release/holderDied never breaks the lease-table invariant" {
    // Property: across any sequence of claims/releases/holder-deaths, the
    // lease engine NEVER produces a state that violates its integrity
    // invariants (no double-grant, no zero-holder/dup-id lease).
    // `auditInvariants()` (the #8A oracle) returning null after every op is
    // the assertion; if the engine ever double-granted, it would catch it.
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    try fb.add("hw:/test/dev0", .claimable, .pcie_function);
    try fb.add("hw:/test/dev1", .claimable, .pcie_function);
    try fb.add("hw:/test/dev2", .claimable, .pcie_function);
    var core = Core.init(testing.allocator, fb.backend());
    defer core.deinit();

    const urns = [_]Urn{
        Urn.from("hw:/test/dev0"),
        Urn.from("hw:/test/dev1"),
        Urn.from("hw:/test/dev2"),
    };
    const modes = [_]model.ClaimMode{ .observe, .shared_rw, .exclusive };
    // CORE-02 — the holder travels with the id now, because `release` is
    // authorized against it. Lease ids are never reused (`next_lease` only
    // increments), so a recorded (id, holder) pair stays correct for the
    // whole run even after the lease is gone.
    const Issued = struct { id: model.LeaseId, holder: model.ClientId };
    var issued: [512]Issued = undefined;
    var issued_n: usize = 0;

    var prng = std.Random.DefaultPrng.init(0xC0DE_F00D_1234);
    const rand = prng.random();
    var i: usize = 0;
    while (i < 3000) : (i += 1) {
        switch (rand.intRangeLessThan(usize, 0, 4)) {
            0 => { // claim — a small URN set so claims collide + the lattice bites
                const urn = urns[rand.intRangeLessThan(usize, 0, urns.len)];
                const mode = modes[rand.intRangeLessThan(usize, 0, modes.len)];
                const holder: model.ClientId = rand.intRangeAtMost(u64, 1, 8);
                if (core.claim(&urn, mode, holder, D.none)) |id| {
                    if (issued_n < issued.len) {
                        issued[issued_n] = .{ .id = id, .holder = holder };
                        issued_n += 1;
                    }
                } else |_| {} // Conflict / Unavailable are fine — not granted
            },
            1 => { // release a (possibly already-released) lease id — idempotent
                if (issued_n > 0) {
                    const pick = issued[rand.intRangeLessThan(usize, 0, issued_n)];
                    // `try`, not `catch {}`: the real holder releasing its own
                    // lease must NEVER be refused, so a NotPermitted here is a
                    // bug in the authorization and should fail the property.
                    try core.release(pick.id, pick.holder, D.none);
                }
            },
            2 => { // CORE-02 — an impostor releases someone else's lease
                if (issued_n > 0) {
                    const pick = issued[rand.intRangeLessThan(usize, 0, issued_n)];
                    const before = core.liveLeaseCount();
                    // Holders are drawn from 1..8, so +1 is always a DIFFERENT
                    // client. Either outcome is acceptable — NotPermitted if the
                    // lease is live, a silent no-op if it was already released —
                    // but the lease table must not shrink either way. That single
                    // assertion covers both without the test needing to know
                    // which case it is in.
                    core.release(pick.id, pick.holder + 1, D.none) catch {};
                    try testing.expectEqual(before, core.liveLeaseCount());
                }
            },
            else => { // a holder "dies" — reclaim all its leases
                _ = core.holderDied(rand.intRangeAtMost(u64, 1, 8));
            },
        }
        // The invariant MUST hold after EVERY op.
        try testing.expect(core.auditInvariants() == null);
    }
}

// ===========================================================================
// R-J-A4-TIMING — a sleeping-backend test fixture (spawned by R2-A4 closure).
//
// FakeBackend.slow_acquire_ms only fails the deadline-BUDGET check (declared
// work vs deadline); it does not actually block. To pin the R2-A4 lock-drop
// *empirically* we need a backend whose `acquire` REALLY sleeps real-time, so a
// concurrent lock-requiring op can be observed completing while a claim is
// parked in backend.acquire (Core.lock dropped, phase 2). This wrapper adds
// exactly that: it delegates every op to a wrapped backend, but `acquire`
// sleeps `sleep_ms` first. Reusable — promote to a shared module if a second
// test wants real-time slowness (it lives here for its sole consumer today).
// ===========================================================================

fn sleepMs(ms: u64) void {
    const ts = std.os.linux.timespec{
        .sec = @intCast(ms / 1000),
        .nsec = @intCast((ms % 1000) * 1_000_000),
    };
    _ = std.os.linux.nanosleep(&ts, null);
}

const SleepingBackend = struct {
    inner: kabi.KernelBackend,
    sleep_ms: u64,

    fn from(ctx: *anyopaque) *SleepingBackend {
        return @ptrCast(@alignCast(ctx));
    }

    // acquire is the ONLY op that sleeps — the point of the fixture.
    fn vAcquire(ctx: *anyopaque, urn: *const Urn, mode: model.ClaimMode, dl: D) Err!kabi.AcquireToken {
        const self = from(ctx);
        sleepMs(self.sleep_ms); // real time — Core.lock is dropped across this (R2-A4)
        return self.inner.acquire(urn, mode, dl);
    }
    // every other op delegates straight through to the wrapped backend.
    fn vEnumerate(ctx: *anyopaque, scope: []const u8, sink: *const kabi.FactSink, dl: D) Err!void {
        return from(ctx).inner.enumerate(scope, sink, dl);
    }
    fn vQueryTopology(ctx: *anyopaque, sink: *const kabi.FactSink, dl: D) Err!void {
        return from(ctx).inner.queryTopology(sink, dl);
    }
    fn vWatch(ctx: *anyopaque, scope: []const u8, sink: *const kabi.EventSink, dl: D) Err!kabi.WatchHandle {
        return from(ctx).inner.watch(scope, sink, dl);
    }
    fn vRelease(ctx: *anyopaque, token: kabi.AcquireToken, dl: D) void {
        from(ctx).inner.release(token, dl);
    }
    fn vReset(ctx: *anyopaque, urn: *const Urn, level: kabi.ResetLevel, dl: D) Err!void {
        return from(ctx).inner.reset(urn, level, dl);
    }
    fn vMapRegion(ctx: *anyopaque, token: kabi.AcquireToken, region: u32, dl: D) Err!kabi.Mapping {
        return from(ctx).inner.mapRegion(token, region, dl);
    }
    fn vRawChannel(ctx: *anyopaque, token: kabi.AcquireToken, dl: D) Err!kabi.RawHandle {
        return from(ctx).inner.rawChannel(token, dl);
    }
    fn vCapabilities(ctx: *anyopaque) kabi.BackendCapabilities {
        return from(ctx).inner.capabilities();
    }
    fn vInspect(ctx: *anyopaque, urn: *const Urn, attrs: *const kabi.AttrSink, dl: D) Err!model.Resource {
        return from(ctx).inner.inspect(urn, attrs, dl);
    }

    const vtable = kabi.KernelBackend.VTable{
        .enumerate = vEnumerate,
        .query_topology = vQueryTopology,
        .watch = vWatch,
        .acquire = vAcquire,
        .release = vRelease,
        .reset = vReset,
        .map_region = vMapRegion,
        .raw_channel = vRawChannel,
        .enforce_cap = null,
        .capabilities = vCapabilities,
        .drain_events = null,
        .acquire_detach = null,
        .inspect = vInspect,
        .inspect_full = null,
        .revoke = null,
        .dump_chain = null,
        .control = null,
        .fd_for_token = null,
    };

    fn backend(self: *SleepingBackend) kabi.KernelBackend {
        return .{ .ctx = self, .vtable = &vtable };
    }
};

test "R-J-A4-TIMING: a lock-only op completes DURING a slow concurrent claim (R2-A4 lock-drop, empirical)" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    try fb.add("hw:/test/slow", .claimable, .pcie_function);
    // Wrap so backend.acquire really sleeps ~500ms (vs FakeBackend's
    // budget-only slowness).
    var sb = SleepingBackend{ .inner = fb.backend(), .sleep_ms = 500 };
    var core = Core.init(testing.allocator, sb.backend());
    defer core.deinit();

    const slow = Urn.from("hw:/test/slow");
    const Shared = struct { core: *Core, urn: *const Urn, done: std.atomic.Value(bool) };
    var sh = Shared{ .core = &core, .urn = &slow, .done = .init(false) };
    const Runner = struct {
        fn run(s: *Shared) void {
            _ = s.core.claim(s.urn, .exclusive, 1, D.none) catch {};
            s.done.store(true, .release);
        }
    };
    var th = try std.Thread.spawn(.{}, Runner.run, .{&sh});
    defer th.join();

    // Let thread A enter backend.acquire — it now sleeps ~500ms with Core.lock
    // DROPPED (R2-A4 phase 2). The claim is provably still in flight.
    sleepMs(80);
    try testing.expect(!sh.done.load(.acquire));

    // A lock-REQUIRING op on THIS core must return promptly. Pre-A4 (lock held
    // across the backend acquire) this would block the remaining ~420ms; with
    // the lock-drop it returns in microseconds.
    const t0 = kabi.nowMs();
    _ = core.liveLeaseCount(); // takes Core.lock
    const elapsed = kabi.nowMs() - t0;
    try testing.expect(elapsed < 150); // did NOT wait on the slow claim's backend sleep
}

// ===========================================================================
// Tier-1 #10 (survivability C2/C4) — fairness / anti-starvation. fairness.zig
// pins the policy in isolation; this pins it END-TO-END through the production
// claimWithCap + release path: under contention a spammer cannot lock out a
// waiting tenant — the freed device goes to the longest-waiting one.
// ===========================================================================

test "#10 anti-starvation: a spammer can't starve a waiter — the freed device goes to the fair waiter" {
    // An UNBOUND cap permits any peer, so one cap + distinct PeerCreds records
    // distinct uids through the real claim path (same trick as the #9 test).
    var ct = cap.CapTable.init(testing.allocator);
    defer ct.deinit();
    const cp = try ct.mint(.{
        .scope = Urn.from("hw:/**"),
        .rights = cap.RightSet.of(&.{ .observe, .claim_exclusive }),
    });

    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    try fb.add("hw:/test/dev0", .claimable, .pcie_function);
    var core = Core.initWithCaps(testing.allocator, fb.backend(), &ct);
    defer core.deinit();

    const urn = Urn.from("hw:/test/dev0");
    const alice = cap.PeerCred{ .uid = 1000, .pid = 100 };
    const bob = cap.PeerCred{ .uid = 1001, .pid = 200 }; // the fair waiter
    const spammer = cap.PeerCred{ .uid = 1002, .pid = 300 };

    // Alice holds the device exclusively.
    const a_lease = try core.claimWithCap(cp, alice, &urn, .exclusive, 1, D.none);
    // Bob wants it — denied (Alice holds it) and recorded as the FIRST waiter.
    try testing.expectError(Err.Conflict, core.claimWithCap(cp, bob, &urn, .exclusive, 2, D.none));
    // The spammer also tries — denied + queued BEHIND Bob.
    try testing.expectError(Err.Conflict, core.claimWithCap(cp, spammer, &urn, .exclusive, 3, D.none));

    // Alice releases → the device is now reserved for Bob (longest-waiting).
    try core.release(a_lease, 1, D.none);

    // The spammer pounces immediately — STILL DENIED: the reservation is Bob's.
    try testing.expectError(Err.Conflict, core.claimWithCap(cp, spammer, &urn, .exclusive, 4, D.none));
    // Bob retries — and WINS. Anti-starvation: the fair waiter got the device
    // despite the spammer racing for it on every release.
    const b_lease = try core.claimWithCap(cp, bob, &urn, .exclusive, 5, D.none);
    try testing.expect(b_lease > 0);

    // Bob releases → the spammer (now the only waiter) finally gets its turn.
    try core.release(b_lease, 5, D.none);
    const s_lease = try core.claimWithCap(cp, spammer, &urn, .exclusive, 6, D.none);
    try testing.expect(s_lease > 0);
}

test "#10 anti-starvation: an uncontended claim is never delayed (no waiters → no reservation)" {
    var ct = cap.CapTable.init(testing.allocator);
    defer ct.deinit();
    const cp = try ct.mint(.{
        .scope = Urn.from("hw:/**"),
        .rights = cap.RightSet.of(&.{ .observe, .claim_exclusive }),
    });
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    try fb.add("hw:/test/dev0", .claimable, .pcie_function);
    var core = Core.initWithCaps(testing.allocator, fb.backend(), &ct);
    defer core.deinit();

    const urn = Urn.from("hw:/test/dev0");
    const alice = cap.PeerCred{ .uid = 1000, .pid = 100 };
    const bob = cap.PeerCred{ .uid = 1001, .pid = 200 };

    // Alice claims + releases with nobody waiting; Bob then claims immediately —
    // no reservation should stand in his way (fairness only engages on contention).
    const a = try core.claimWithCap(cp, alice, &urn, .exclusive, 1, D.none);
    try core.release(a, 1, D.none);
    const b = try core.claimWithCap(cp, bob, &urn, .exclusive, 2, D.none);
    try testing.expect(b > 0);
}

// ===========================================================================
// #10 §5.4 — active holder-preemption, END-TO-END. The fairness DECISION +
// grace record are pinned in fairness.zig; these pin the EXECUTION through the
// real Core: the claim-path hook marks a holder, and `runDuePreemptions` forces
// the §3.4 teardown (backend.revoke below the fd → Err.Revoked) and hands the
// device to the higher-priority waiter — with the graceful path + the no-source
// / same-tier negative controls verifying the mechanism is non-vacuous.
// ===========================================================================

/// Test priority policy: one designated uid is high-priority (10), all others 0.
const PrioTier = struct {
    hi_uid: u32,
    fn get(ctx: *anyopaque, uid: u32) u8 {
        const self: *PrioTier = @ptrCast(@alignCast(ctx));
        return if (uid == self.hi_uid) 10 else 0;
    }
};

test "#10 §5.4: a higher-priority denied claim MARKS the live holder for preemption" {
    var ct = cap.CapTable.init(testing.allocator);
    defer ct.deinit();
    const cp = try ct.mint(.{ .scope = Urn.from("hw:/**"), .rights = cap.RightSet.of(&.{ .observe, .claim_exclusive }) });
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    try fb.add("hw:/test/dev0", .claimable, .pcie_function);
    var core = Core.initWithCaps(testing.allocator, fb.backend(), &ct);
    defer core.deinit();
    var tier = PrioTier{ .hi_uid = 1001 };
    core.fairness.setPrioritySource(.{ .ctx = &tier, .get = PrioTier.get });

    const urn = Urn.from("hw:/test/dev0");
    const lo = cap.PeerCred{ .uid = 1000, .pid = 1 };
    const hi = cap.PeerCred{ .uid = 1001, .pid = 2 };

    // Low-priority tenant holds it exclusively; high-priority tenant is denied —
    // and because it outranks the holder, the holder is marked for preemption.
    _ = try core.claimWithCap(cp, lo, &urn, .exclusive, 1, D.none);
    try testing.expectError(Err.Conflict, core.claimWithCap(cp, hi, &urn, .exclusive, 2, D.none));
    try testing.expect(core.fairness.isPreemptionPending(&urn));
}

test "#10 §5.4 negative control: a SAME-priority denied claim marks NO preemption" {
    var ct = cap.CapTable.init(testing.allocator);
    defer ct.deinit();
    const cp = try ct.mint(.{ .scope = Urn.from("hw:/**"), .rights = cap.RightSet.of(&.{ .observe, .claim_exclusive }) });
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    try fb.add("hw:/test/dev0", .claimable, .pcie_function);
    var core = Core.initWithCaps(testing.allocator, fb.backend(), &ct);
    defer core.deinit();
    var tier = PrioTier{ .hi_uid = 9999 }; // neither tenant is the high uid → both prio 0
    core.fairness.setPrioritySource(.{ .ctx = &tier, .get = PrioTier.get });

    const urn = Urn.from("hw:/test/dev0");
    const a = cap.PeerCred{ .uid = 1000, .pid = 1 };
    const b = cap.PeerCred{ .uid = 1001, .pid = 2 };
    _ = try core.claimWithCap(cp, a, &urn, .exclusive, 1, D.none);
    try testing.expectError(Err.Conflict, core.claimWithCap(cp, b, &urn, .exclusive, 2, D.none));
    // Equal priority → no eviction of a peer; only the FIFO reservation applies.
    try testing.expect(!core.fairness.isPreemptionPending(&urn));
}

test "#10 §5.4: runDuePreemptions force-revokes a past-grace holder and hands the device to the waiter" {
    var ct = cap.CapTable.init(testing.allocator);
    defer ct.deinit();
    const cp = try ct.mint(.{ .scope = Urn.from("hw:/**"), .rights = cap.RightSet.of(&.{ .observe, .claim_exclusive }) });
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    try fb.add("hw:/test/dev0", .claimable, .pcie_function);
    var core = Core.initWithCaps(testing.allocator, fb.backend(), &ct);
    defer core.deinit();
    var tier = PrioTier{ .hi_uid = 1001 };
    core.fairness.setPrioritySource(.{ .ctx = &tier, .get = PrioTier.get });

    const urn = Urn.from("hw:/test/dev0");
    const lo = cap.PeerCred{ .uid = 1000, .pid = 1 };
    const hi = cap.PeerCred{ .uid = 1001, .pid = 2 };

    const lo_lease = try core.claimWithCap(cp, lo, &urn, .exclusive, 1, D.none); // holder id 1
    try testing.expectError(Err.Conflict, core.claimWithCap(cp, hi, &urn, .exclusive, 2, D.none));
    try testing.expect(core.fairness.isPreemptionPending(&urn));

    // BEFORE the grace window passes: nothing is torn down; the holder keeps it.
    try testing.expectEqual(@as(usize, 0), core.runDuePreemptions(0, D.none));
    try testing.expectEqual(@as(usize, 1), core.liveLeaseCount());

    // Well past the grace window: the low-priority holder is force-revoked.
    const t_future = kabi.nowMs() + 1_000_000; // far beyond the 3 s GRACE_MS
    try testing.expectEqual(@as(usize, 1), core.runDuePreemptions(t_future, D.none));
    try testing.expectEqual(@as(usize, 0), core.liveLeaseCount()); // its lease is gone
    // The holder learns via Err.Revoked (preempted), NOT InvalidToken (never had it).
    try testing.expectError(Err.Revoked, core.raw(lo_lease, 1, D.none));
    // …and the device is now reserved for + claimable by the high-priority waiter.
    const hi_lease = try core.claimWithCap(cp, hi, &urn, .exclusive, 3, D.none);
    try testing.expect(hi_lease > 0);
}

test "#10 §5.4 graceful: a holder that RELEASES within grace is never force-revoked" {
    var ct = cap.CapTable.init(testing.allocator);
    defer ct.deinit();
    const cp = try ct.mint(.{ .scope = Urn.from("hw:/**"), .rights = cap.RightSet.of(&.{ .observe, .claim_exclusive }) });
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    try fb.add("hw:/test/dev0", .claimable, .pcie_function);
    var core = Core.initWithCaps(testing.allocator, fb.backend(), &ct);
    defer core.deinit();
    var tier = PrioTier{ .hi_uid = 1001 };
    core.fairness.setPrioritySource(.{ .ctx = &tier, .get = PrioTier.get });

    const urn = Urn.from("hw:/test/dev0");
    const lo = cap.PeerCred{ .uid = 1000, .pid = 1 };
    const hi = cap.PeerCred{ .uid = 1001, .pid = 2 };

    const lo_lease = try core.claimWithCap(cp, lo, &urn, .exclusive, 1, D.none);
    try testing.expectError(Err.Conflict, core.claimWithCap(cp, hi, &urn, .exclusive, 2, D.none));
    try testing.expect(core.fairness.isPreemptionPending(&urn));

    // The holder releases VOLUNTARILY within its grace window → preemption cancelled.
    try core.release(lo_lease, 1, D.none);
    try testing.expect(!core.fairness.isPreemptionPending(&urn));
    // Even far past the original deadline, NOTHING is torn down (no spurious revoke).
    const t_future = kabi.nowMs() + 1_000_000;
    try testing.expectEqual(@as(usize, 0), core.runDuePreemptions(t_future, D.none));
    // The waiter claims the cleanly-released device.
    const hi_lease = try core.claimWithCap(cp, hi, &urn, .exclusive, 3, D.none);
    try testing.expect(hi_lease > 0);
}

// ===========================================================================
// R-T1-8 residual (survivability I3) — helper-mid-op in-flight quarantine.
// When the Tier-0 #3 supervisor kills the privileged helper mid-op, the device
// state is unknown. The acquire path already quarantines on Err.Timeout; these
// pin the same safety net for `raw` + `control`. A test wrapper returns a
// configured error for those ops (FakeBackend has no raw/control timeout knob).
// ===========================================================================

/// B1-F01 — a shared, ordered log of "what happened when" across the
/// backend seam and the event seam. `'r'` = `backend.release` entered,
/// `'p'` = an event was pushed to the sink. The resulting string IS the
/// interleaving, so an ordering contract becomes a string comparison.
const OrderRecord = struct {
    ops: [64]u8 = undefined,
    n: usize = 0,
    mu: kabi.SpinMutex = .{},

    fn note(self: *OrderRecord, c: u8) void {
        self.mu.lock();
        defer self.mu.unlock();
        if (self.n < self.ops.len) {
            self.ops[self.n] = c;
            self.n += 1;
        }
    }

    fn seq(self: *OrderRecord) []const u8 {
        self.mu.lock();
        defer self.mu.unlock();
        return self.ops[0..self.n];
    }

    fn sink(self: *OrderRecord) EventSink {
        return .{ .ctx = self, .push = pushEvent };
    }

    fn pushEvent(ctx: ?*anyopaque, ev: model.Event) void {
        _ = ev;
        const self: *OrderRecord = @ptrCast(@alignCast(ctx.?));
        self.note('p');
    }
};

const OpFaultBackend = struct {
    inner: kabi.KernelBackend,
    raw_err: ?Err = null,
    control_err: ?Err = null,
    /// B1-F01 — when set, `release` records itself here.
    order: ?*OrderRecord = null,
    /// M-B B1 — FakeBackend has no `control` slot (nothing writable to
    /// fake), so a SUCCESSFUL control needs a stand-in. Off by default,
    /// which leaves every pre-B1 use of this fixture untouched.
    control_ok: bool = false,

    fn from(ctx: *anyopaque) *OpFaultBackend {
        return @ptrCast(@alignCast(ctx));
    }
    fn vRawChannel(ctx: *anyopaque, token: kabi.AcquireToken, dl: D) Err!kabi.RawHandle {
        const self = from(ctx);
        if (self.raw_err) |e| return e; // simulate a helper fault mid-raw
        return self.inner.rawChannel(token, dl);
    }
    fn vControl(ctx: *anyopaque, urn: *const Urn, verb: model.ControlVerb, value: []const u8, cap_id: u64, dl: D) Err!kabi.ControlOutcome {
        const self = from(ctx);
        if (self.control_err) |e| return e; // simulate a helper fault mid-control
        if (self.control_ok) return kabi.ControlOutcome{ .generation = 1 };
        return self.inner.control(urn, verb, value, cap_id, dl);
    }
    // everything else delegates to the wrapped backend.
    fn vEnumerate(ctx: *anyopaque, scope: []const u8, sink: *const kabi.FactSink, dl: D) Err!void {
        return from(ctx).inner.enumerate(scope, sink, dl);
    }
    fn vQueryTopology(ctx: *anyopaque, sink: *const kabi.FactSink, dl: D) Err!void {
        return from(ctx).inner.queryTopology(sink, dl);
    }
    fn vWatch(ctx: *anyopaque, scope: []const u8, sink: *const kabi.EventSink, dl: D) Err!kabi.WatchHandle {
        return from(ctx).inner.watch(scope, sink, dl);
    }
    fn vAcquire(ctx: *anyopaque, urn: *const Urn, mode: model.ClaimMode, dl: D) Err!kabi.AcquireToken {
        return from(ctx).inner.acquire(urn, mode, dl);
    }
    fn vRelease(ctx: *anyopaque, token: kabi.AcquireToken, dl: D) void {
        const self = from(ctx);
        // B1-F01 — note the hardware release in the shared interleaving
        // log, so an ordering pin can assert it happened BEFORE the event.
        if (self.order) |rec| rec.note('r');
        self.inner.release(token, dl);
    }
    fn vReset(ctx: *anyopaque, urn: *const Urn, level: kabi.ResetLevel, dl: D) Err!void {
        return from(ctx).inner.reset(urn, level, dl);
    }
    fn vMapRegion(ctx: *anyopaque, token: kabi.AcquireToken, region: u32, dl: D) Err!kabi.Mapping {
        return from(ctx).inner.mapRegion(token, region, dl);
    }
    fn vCapabilities(ctx: *anyopaque) kabi.BackendCapabilities {
        return from(ctx).inner.capabilities();
    }
    fn vInspect(ctx: *anyopaque, urn: *const Urn, attrs: *const kabi.AttrSink, dl: D) Err!model.Resource {
        return from(ctx).inner.inspect(urn, attrs, dl);
    }
    /// M-B B1 — delegated so this fixture can also drive `containByFlooding`
    /// (which tears down through `backend.revoke` before quarantining).
    fn vRevoke(ctx: *anyopaque, urn: *const Urn, dl: D) Err!void {
        return from(ctx).inner.revoke(urn, dl);
    }

    const vtable = kabi.KernelBackend.VTable{
        .enumerate = vEnumerate,
        .query_topology = vQueryTopology,
        .watch = vWatch,
        .acquire = vAcquire,
        .release = vRelease,
        .reset = vReset,
        .map_region = vMapRegion,
        .raw_channel = vRawChannel,
        .enforce_cap = null,
        .capabilities = vCapabilities,
        .drain_events = null,
        .acquire_detach = null,
        .inspect = vInspect,
        .inspect_full = null,
        .revoke = vRevoke,
        .dump_chain = null,
        .control = vControl,
        .fd_for_token = null,
    };

    fn backend(self: *OpFaultBackend) kabi.KernelBackend {
        return .{ .ctx = self, .vtable = &vtable };
    }
};

test "I3 helper-fault: a raw_channel TIMEOUT (helper killed mid-op) quarantines the device" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    try fb.add("hw:/test/dev0", .claimable, .pcie_function);
    var ofb = OpFaultBackend{ .inner = fb.backend(), .raw_err = Err.Timeout };
    var core = Core.init(testing.allocator, ofb.backend());
    defer core.deinit();

    const urn = Urn.from("hw:/test/dev0");
    const lease = try core.claim(&urn, .exclusive, 1, D.none);
    // raw hits the helper, which is killed mid-op → Err.Timeout. The device
    // state is now unknown, so the URN must be quarantined.
    try testing.expectError(Err.Timeout, core.raw(lease, 1, D.none));
    try testing.expect(core.quarantineStatus(&urn) != null);
    // A subsequent claim is refused until an operator recovers it (#12).
    try core.release(lease, 1, D.none);
    try testing.expectError(Err.Unavailable, core.claim(&urn, .exclusive, 2, D.fromNow(1000)));
}

test "I3 helper-fault: a raw_channel CLEAN failure does NOT quarantine (state is known)" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    try fb.add("hw:/test/dev0", .claimable, .pcie_function);
    var ofb = OpFaultBackend{ .inner = fb.backend(), .raw_err = Err.HardwareFault };
    var core = Core.init(testing.allocator, ofb.backend());
    defer core.deinit();

    const urn = Urn.from("hw:/test/dev0");
    const lease = try core.claim(&urn, .exclusive, 1, D.none);
    // A HardwareFault is a clean failure — the device state is KNOWN, so it is
    // NOT quarantined (only a timeout means "unknown").
    try testing.expectError(Err.HardwareFault, core.raw(lease, 1, D.none));
    try testing.expect(core.quarantineStatus(&urn) == null);
    try core.release(lease, 1, D.none);
    const release = try core.claim(&urn, .exclusive, 2, D.fromNow(1000)); // still claimable
    try testing.expect(release > 0);
}

test "I3 helper-fault: a control TIMEOUT (helper killed mid-op) quarantines the device" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    try fb.add("hw:/test/dev0", .claimable, .pcie_function);
    var ofb = OpFaultBackend{ .inner = fb.backend(), .control_err = Err.Timeout };
    var core = Core.init(testing.allocator, ofb.backend());
    defer core.deinit();

    const urn = Urn.from("hw:/test/dev0");
    try testing.expectError(Err.Timeout, core.control(&urn, .set_authorized, "1", 0, D.none));
    try testing.expect(core.quarantineStatus(&urn) != null);
}

// ---------------------------------------------------------------------------
// M-B B1 — THE CORE EMITS.
//
// Every one of these pins asserts two things at once:
//   * the payload (right kind, right URN, right old/new) — "emitted iff the
//     mutation committed", per site, success AND failure;
//   * the lock order — `EventCollector.push` fails the test if the emitting
//     thread still holds `Core.lock`, and additionally calls back INTO the
//     core (`liveLeaseCount`, which takes that same lock) to prove the
//     re-entrancy the D-013 discipline is supposed to buy. If a publish ever
//     migrated back under the guard, the assertion trips first; were the
//     assertion itself removed, the re-entrant call would deadlock the test.
// ---------------------------------------------------------------------------

const EventSink = coremod.EventSink;

/// Records everything the core emits, and polices the lock order while it
/// does. Thread-safe: the threaded pins publish from several threads at once.
const EventCollector = struct {
    /// 96 > MAX_EVENT_BATCH (64) + its overflow gap, so the overflow pin can
    /// see the whole truncated batch AND the gap that confesses it.
    events: [96]model.Event = undefined,
    n: usize = 0,
    /// Non-zero ⇒ a publish ran with the core lock held by this thread.
    lock_violations: usize = 0,
    /// Set to police the lock order + exercise re-entrancy.
    core: ?*Core = null,
    mu: kabi.SpinMutex = .{},

    fn sink(self: *EventCollector) EventSink {
        return .{ .ctx = self, .push = push };
    }

    fn push(ctx: ?*anyopaque, ev: model.Event) void {
        const self: *EventCollector = @ptrCast(@alignCast(ctx.?));
        var violated = false;
        if (self.core) |c| {
            violated = c.lockHeldBySelf();
            // Re-entrancy proof: a lock-taking Core op from inside the sink.
            // Under a correct publish this returns; under a publish moved
            // back inside the guard it self-deadlocks on the SpinMutex.
            if (!violated) _ = c.liveLeaseCount();
        }
        self.mu.lock();
        defer self.mu.unlock();
        if (violated) self.lock_violations += 1;
        if (self.n < self.events.len) {
            self.events[self.n] = ev;
            self.n += 1;
        }
    }

    fn reset(self: *EventCollector) void {
        self.mu.lock();
        defer self.mu.unlock();
        self.n = 0;
    }

    fn count(self: *EventCollector) usize {
        self.mu.lock();
        defer self.mu.unlock();
        return self.n;
    }

    fn countOf(self: *EventCollector, kind: std.meta.Tag(model.Event)) usize {
        self.mu.lock();
        defer self.mu.unlock();
        var k: usize = 0;
        for (self.events[0..self.n]) |e| {
            if (std.meta.activeTag(e) == kind) k += 1;
        }
        return k;
    }
};

/// Build a core over a seeded fake, with the collector wired as its sink and
/// policing its lock. Returns the collector already pointed at the core.
fn wireCollector(col: *EventCollector, core: *Core) void {
    col.core = core;
    core.setEventSink(col.sink());
}

test "B1 claim: a committed grant emits exactly one ownership_changed" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    var core = Core.init(testing.allocator, try seeded(&fb));
    defer core.deinit();
    var col = EventCollector{};
    wireCollector(&col, &core);

    const urn = Urn.from("hw:/pci/0000:01:00.0/fn0");
    const id = try core.claim(&urn, .exclusive, 42, D.none);
    try testing.expect(id != 0);

    try testing.expectEqual(@as(usize, 1), col.count());
    try testing.expect(col.events[0] == .ownership_changed);
    const oc = col.events[0].ownership_changed;
    try testing.expectEqualStrings(urn.slice(), oc.urn.slice());
    try testing.expect(oc.old == null);
    try testing.expectEqual(@as(model.ClientId, 42), oc.new.?);
    try testing.expectEqual(@as(usize, 0), col.lock_violations);
}

test "B1 claim: a claim REFUSED by the lattice emits nothing" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    var core = Core.init(testing.allocator, try seeded(&fb));
    defer core.deinit();
    var col = EventCollector{};
    wireCollector(&col, &core);

    const urn = Urn.from("hw:/pci/0000:01:00.0/fn0");
    _ = try core.claim(&urn, .exclusive, 1, D.none);
    col.reset(); // forget the grant; we are pinning the REFUSAL

    try testing.expectError(Err.Conflict, core.claim(&urn, .exclusive, 2, D.none));
    try testing.expectEqual(@as(usize, 0), col.count());
    try testing.expectEqual(@as(usize, 0), col.lock_violations);
}

test "B1 claim: a claim refused because the URN is quarantined emits nothing" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    var core = Core.init(testing.allocator, try seeded(&fb));
    defer core.deinit();
    const urn = Urn.from("hw:/pci/0000:01:00.0/fn0");
    try quarantineViaTimeout(&core, &fb, &urn);

    // Wire the sink only AFTER the quarantine, so the refusal is all we see.
    var col = EventCollector{};
    wireCollector(&col, &core);
    try testing.expectError(Err.Unavailable, core.claim(&urn, .exclusive, 1, D.none));
    try testing.expectEqual(@as(usize, 0), col.count());
    try testing.expectEqual(@as(usize, 0), col.lock_violations);
}

test "B1 claim: an acquire TIMEOUT emits the quarantine's faulted and NO ownership event" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    try fb.add("hw:/pci/slow/fn0", .claimable, .pcie_function);
    fb.slow_acquire_ms = 5000; // declared work exceeds the deadline below
    var core = Core.init(testing.allocator, fb.backend());
    defer core.deinit();
    var col = EventCollector{};
    wireCollector(&col, &core);

    const urn = Urn.from("hw:/pci/slow/fn0");
    try testing.expectError(Err.Timeout, core.claim(&urn, .exclusive, 1, D.fromNow(10)));

    // The GRANT did not commit — no ownership_changed. The QUARANTINE did —
    // one faulted, carrying the reason. The EXACT total matters as much as
    // the per-kind counts: an event smuggled onto the rollback path would
    // otherwise be absorbed by the batch's overflow (and confessed only as a
    // gap), which is not a thing this pin may tolerate.
    try testing.expectEqual(@as(usize, 1), col.count());
    try testing.expectEqual(@as(usize, 0), col.countOf(.ownership_changed));
    try testing.expectEqual(@as(usize, 1), col.countOf(.faulted));
    try testing.expectEqual(
        @as(u32, @intFromEnum(model.QuarantineReason.op_timeout)),
        col.events[0].faulted.code,
    );
    try testing.expectEqual(@as(usize, 0), col.lock_violations);
}

test "B1 release: a committed release emits one ownership_changed to nobody" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    var core = Core.init(testing.allocator, try seeded(&fb));
    defer core.deinit();
    const urn = Urn.from("hw:/usb/bus1/dev4/if0");
    const id = try core.claim(&urn, .exclusive, 7, D.none);

    var col = EventCollector{};
    wireCollector(&col, &core);
    try core.release(id, 7, D.none);

    try testing.expectEqual(@as(usize, 1), col.count());
    const oc = col.events[0].ownership_changed;
    try testing.expectEqualStrings(urn.slice(), oc.urn.slice());
    try testing.expectEqual(@as(model.ClientId, 7), oc.old.?);
    try testing.expect(oc.new == null);
    try testing.expectEqual(@as(usize, 0), col.lock_violations);
}

test "B1 release: the idempotent no-op and the refused release both emit nothing" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    var core = Core.init(testing.allocator, try seeded(&fb));
    defer core.deinit();
    const urn = Urn.from("hw:/usb/bus1/dev4/if0");
    const id = try core.claim(&urn, .exclusive, 7, D.none);

    var col = EventCollector{};
    wireCollector(&col, &core);

    try core.release(9999, 7, D.none); // unknown id — silent no-op
    try testing.expectEqual(@as(usize, 0), col.count());

    try testing.expectError(Err.NotPermitted, core.release(id, 8, D.none)); // not yours
    try testing.expectEqual(@as(usize, 0), col.count());

    try core.release(id, 7, D.none); // the real one
    try testing.expectEqual(@as(usize, 1), col.count());

    try core.release(id, 7, D.none); // double-release — still a no-op
    try testing.expectEqual(@as(usize, 1), col.count());
    try testing.expectEqual(@as(usize, 0), col.lock_violations);
}

test "B1 holderDied: one ownership_changed per reclaimed lease" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    try fb.add("hw:/pci/a/fn0", .claimable, .pcie_function);
    try fb.add("hw:/pci/b/fn0", .claimable, .pcie_function);
    try fb.add("hw:/pci/c/fn0", .claimable, .pcie_function);
    var core = Core.init(testing.allocator, fb.backend());
    defer core.deinit();

    const a = Urn.from("hw:/pci/a/fn0");
    const b = Urn.from("hw:/pci/b/fn0");
    const c = Urn.from("hw:/pci/c/fn0");
    _ = try core.claim(&a, .exclusive, 5, D.none);
    _ = try core.claim(&b, .exclusive, 5, D.none);
    _ = try core.claim(&c, .exclusive, 6, D.none); // another client — untouched

    var col = EventCollector{};
    wireCollector(&col, &core);
    try testing.expectEqual(@as(usize, 2), core.holderDied(5));

    try testing.expectEqual(@as(usize, 2), col.count());
    for (col.events[0..2]) |e| {
        const oc = e.ownership_changed;
        try testing.expectEqual(@as(model.ClientId, 5), oc.old.?);
        try testing.expect(oc.new == null);
        try testing.expect(!std.mem.eql(u8, oc.urn.slice(), c.slice())); // never client 6's
    }
    try testing.expectEqual(@as(usize, 0), col.lock_violations);
}

test "B1 holderDied: a mid-flight claim (placeholder) announces nothing — it never announced a grant" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    try fb.add("hw:/test/slow", .claimable, .pcie_function);
    var sb = SleepingBackend{ .inner = fb.backend(), .sleep_ms = 400 };
    var core = Core.init(testing.allocator, sb.backend());
    defer core.deinit();
    var col = EventCollector{};
    wireCollector(&col, &core);

    const Slow = struct {
        fn run(cr: *Core) void {
            const u = Urn.from("hw:/test/slow");
            // Returns Err.Conflict once holderDied removes the placeholder.
            _ = cr.claim(&u, .exclusive, 11, D.none) catch {};
        }
    };
    const t = try std.Thread.spawn(.{}, Slow.run, .{&core});
    sleepMs(120); // the placeholder is now in the table, token.id == 0
    try testing.expectEqual(@as(usize, 1), core.liveLeaseCount());
    try testing.expectEqual(@as(usize, 0), core.holderDied(11)); // 0 committed tokens
    t.join();

    // No grant was ever announced, so no loss may be either.
    try testing.expectEqual(@as(usize, 0), col.count());
    try testing.expectEqual(@as(usize, 0), col.lock_violations);
}

test "B1 revoke: markRevokedByUrn emits one ownership_changed per dropped lease" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    var core = Core.init(testing.allocator, try seeded(&fb));
    defer core.deinit();
    const urn = Urn.from("hw:/usb/bus1/dev4/if0");
    _ = try core.claim(&urn, .observe, 1, D.none);
    _ = try core.claim(&urn, .observe, 2, D.none);

    var col = EventCollector{};
    wireCollector(&col, &core);
    core.markRevokedByUrn(&urn);

    try testing.expectEqual(@as(usize, 2), col.count());
    for (col.events[0..2]) |e| {
        try testing.expectEqualStrings(urn.slice(), e.ownership_changed.urn.slice());
        try testing.expect(e.ownership_changed.new == null);
    }
    // Idempotent second revoke: nothing left to drop, nothing to announce.
    col.reset();
    core.markRevokedByUrn(&urn);
    try testing.expectEqual(@as(usize, 0), col.count());
    try testing.expectEqual(@as(usize, 0), col.lock_violations);
}

test "B1 batch overflow is GAP-HONEST, never a silent truncation" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    try fb.add("hw:/pci/crowd/fn0", .claimable, .pcie_function);
    var core = Core.init(testing.allocator, fb.backend());
    defer core.deinit();

    // Observe never conflicts, so one URN can carry more holders than one
    // event batch holds (MAX_EVENT_BATCH = 64).
    const urn = Urn.from("hw:/pci/crowd/fn0");
    const N = coremod.MAX_EVENT_BATCH + 1;
    var i: usize = 0;
    while (i < N) : (i += 1) {
        _ = try core.claim(&urn, .observe, @intCast(i + 1), D.none);
    }

    var col = EventCollector{};
    wireCollector(&col, &core);
    core.markRevokedByUrn(&urn); // 65 losses into a 64-slot batch

    try testing.expectEqual(@as(usize, coremod.MAX_EVENT_BATCH), col.countOf(.ownership_changed));
    try testing.expectEqual(@as(usize, 1), col.countOf(.gap));
    // The gap is LAST — the consumer reads what survived, then learns it
    // missed something and re-enumerates.
    const last = col.events[col.count() - 1];
    try testing.expect(last == .gap);
    try testing.expectEqual(model.GapSource.backend_internal, last.gap.source);
    try testing.expectEqual(@as(usize, 0), col.lock_violations);
}

test "B1 quarantine: a set emits faulted with the reason; a re-set of the same URN emits nothing" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    try fb.add("hw:/test/dev0", .claimable, .pcie_function);
    var ofb = OpFaultBackend{ .inner = fb.backend(), .control_err = Err.Timeout };
    var core = Core.init(testing.allocator, ofb.backend());
    defer core.deinit();
    var col = EventCollector{};
    wireCollector(&col, &core);

    const urn = Urn.from("hw:/test/dev0");
    try testing.expectError(Err.Timeout, core.control(&urn, .set_authorized, "1", 0, D.none));
    try testing.expectEqual(@as(usize, 1), col.count());
    try testing.expect(col.events[0] == .faulted);
    try testing.expectEqualStrings(urn.slice(), col.events[0].faulted.urn.slice());
    try testing.expectEqual(
        @as(u32, @intFromEnum(model.QuarantineReason.op_timeout)),
        col.events[0].faulted.code,
    );

    // Already quarantined: markQuarantined is idempotent, so it is NOT a
    // mutation and announces nothing.
    col.reset();
    try testing.expectError(Err.Timeout, core.control(&urn, .set_authorized, "1", 0, D.none));
    try testing.expectEqual(@as(usize, 0), col.count());
    try testing.expectEqual(@as(usize, 0), col.lock_violations);
}

test "B1 quarantine: a clear emits state_changed quarantined→free; a no-op clear emits nothing" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    try fb.add("hw:/test/dev0", .claimable, .pcie_function);
    var core = Core.init(testing.allocator, fb.backend());
    defer core.deinit();
    const urn = Urn.from("hw:/test/dev0");
    try quarantineViaTimeout(&core, &fb, &urn);

    var col = EventCollector{};
    wireCollector(&col, &core);
    try testing.expect(core.clearQuarantine(&urn));

    try testing.expectEqual(@as(usize, 1), col.count());
    const sc = col.events[0].state_changed;
    try testing.expectEqualStrings(urn.slice(), sc.urn.slice());
    try testing.expect(sc.old == .quarantined);
    try testing.expectEqual(model.QuarantineReason.op_timeout, sc.old.quarantined.reason);
    try testing.expect(sc.new == .free);

    col.reset();
    try testing.expect(!core.clearQuarantine(&urn)); // no-op
    try testing.expectEqual(@as(usize, 0), col.count());
    try testing.expectEqual(@as(usize, 0), col.lock_violations);
}

test "B1 #12 ladder: a recovered device announces exactly one return to free" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    try fb.add("hw:/test/dev0", .claimable, .pcie_function);
    var core = Core.init(testing.allocator, fb.backend());
    defer core.deinit();
    const urn = Urn.from("hw:/test/dev0");
    try quarantineViaTimeout(&core, &fb, &urn);

    var col = EventCollector{};
    wireCollector(&col, &core);
    try testing.expectEqual(coremod.RecoveryOutcome.recovered_flr, core.recoverByReset(&urn, D.none));

    try testing.expectEqual(@as(usize, 1), col.count());
    try testing.expect(col.events[0].state_changed.new == .free);
    try testing.expectEqual(@as(usize, 0), col.lock_violations);
}

test "B1 #12 ladder: a failed recovery re-escalates in place — one faulted, and NEVER a free window" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    try fb.add("hw:/test/dev0", .claimable, .pcie_function);
    var core = Core.init(testing.allocator, fb.backend());
    defer core.deinit();
    const urn = Urn.from("hw:/test/dev0");
    try quarantineViaTimeout(&core, &fb, &urn);
    fb.can_reset = false; // both rungs fail

    var col = EventCollector{};
    wireCollector(&col, &core);
    try testing.expectEqual(coremod.RecoveryOutcome.still_quarantined, core.recoverByReset(&urn, D.none));

    // Pre-B1 this path was clear-then-mark, which would have announced a
    // `state_changed → free` the resource never had (and briefly made it
    // claimable). Exactly one event, and it is the escalation.
    try testing.expectEqual(@as(usize, 1), col.count());
    try testing.expect(col.events[0] == .faulted);
    try testing.expectEqual(
        @as(u32, @intFromEnum(model.QuarantineReason.reset_unverified)),
        col.events[0].faulted.code,
    );
    try testing.expectEqual(@as(usize, 0), col.countOf(.state_changed));
    // ...and the record still says quarantined, with the escalated reason.
    const q = core.quarantineStatus(&urn).?;
    try testing.expectEqual(model.QuarantineReason.reset_unverified, q.reason);
    try testing.expectEqual(@as(usize, 0), col.lock_violations);
}

test "B1 containByFlooding: the tear-down announces the loss AND the fault" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    try fb.add("hw:/pci/flood/fn0", .claimable, .pcie_function);
    var core = Core.init(testing.allocator, fb.backend());
    defer core.deinit();
    const urn = Urn.from("hw:/pci/flood/fn0");
    _ = try core.claim(&urn, .exclusive, 3, D.none);

    var col = EventCollector{};
    wireCollector(&col, &core);
    try core.containByFlooding(&urn, D.none);

    try testing.expectEqual(@as(usize, 2), col.count());
    try testing.expect(col.events[0] == .ownership_changed); // holder lost it...
    try testing.expectEqual(@as(model.ClientId, 3), col.events[0].ownership_changed.old.?);
    try testing.expect(col.events[1] == .faulted); // ...because it faulted
    try testing.expectEqual(
        @as(u32, @intFromEnum(model.QuarantineReason.fault_maybe_dirty)),
        col.events[1].faulted.code,
    );
    try testing.expectEqual(@as(usize, 0), col.lock_violations);
}

test "B1 control: a landed write emits one state_changed; a refused write emits none" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    try fb.add("hw:/test/dev0", .claimable, .pcie_function);
    var ofb = OpFaultBackend{ .inner = fb.backend(), .control_ok = true };
    var core = Core.init(testing.allocator, ofb.backend());
    defer core.deinit();
    var col = EventCollector{};
    wireCollector(&col, &core);

    const urn = Urn.from("hw:/test/dev0");
    _ = try core.control(&urn, .set_authorized, "1", 0, D.none);
    try testing.expectEqual(@as(usize, 1), col.count());
    try testing.expect(col.events[0] == .state_changed);
    try testing.expectEqualStrings(urn.slice(), col.events[0].state_changed.urn.slice());

    // A clean refusal is not a mutation: nothing lands, nothing is said, and
    // (unlike a Timeout) nothing is quarantined either.
    col.reset();
    ofb.control_ok = false;
    ofb.control_err = Err.HardwareFault;
    try testing.expectError(Err.HardwareFault, core.control(&urn, .set_authorized, "1", 0, D.none));
    try testing.expectEqual(@as(usize, 0), col.count());
    try testing.expectEqual(@as(usize, 0), col.lock_violations);
}

test "B1 reconcile: each newly-quarantined orphan is announced once" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    var core = Core.init(testing.allocator, try seeded(&fb));
    defer core.deinit();
    const held = Urn.from("hw:/pci/0000:01:00.0/fn0");
    _ = try core.claim(&held, .exclusive, 1, D.none);

    var col = EventCollector{};
    wireCollector(&col, &core);
    const orphan = Urn.from("hw:/usb/bus1/dev4/if0");
    const bound = [_]Urn{ held, orphan };
    try testing.expectEqual(@as(usize, 1), core.reconcileAfterRestart(&bound));

    try testing.expectEqual(@as(usize, 1), col.count()); // the held one is left alone
    try testing.expectEqualStrings(orphan.slice(), col.events[0].faulted.urn.slice());
    try testing.expectEqual(
        @as(u32, @intFromEnum(model.QuarantineReason.unclaimed_after_restart)),
        col.events[0].faulted.code,
    );

    // Idempotent re-run: already quarantined ⇒ no mutation ⇒ no event.
    col.reset();
    try testing.expectEqual(@as(usize, 0), core.reconcileAfterRestart(&bound));
    try testing.expectEqual(@as(usize, 0), col.count());
    try testing.expectEqual(@as(usize, 0), col.lock_violations);
}

test "B1 lock order: EVERY emitting site publishes with the core lock released" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    try fb.add("hw:/pci/x/fn0", .claimable, .pcie_function);
    try fb.add("hw:/pci/y/fn0", .claimable, .pcie_function);
    try fb.add("hw:/pci/z/fn0", .claimable, .pcie_function);
    var ofb = OpFaultBackend{ .inner = fb.backend(), .control_ok = true };
    var core = Core.init(testing.allocator, ofb.backend());
    defer core.deinit();
    var col = EventCollector{};
    wireCollector(&col, &core);

    const x = Urn.from("hw:/pci/x/fn0");
    const y = Urn.from("hw:/pci/y/fn0");
    const z = Urn.from("hw:/pci/z/fn0");

    const idx = try core.claim(&x, .exclusive, 1, D.none); // claim
    try core.release(idx, 1, D.none); // release
    _ = try core.claim(&y, .exclusive, 2, D.none);
    _ = core.holderDied(2); // holderDied
    _ = try core.claim(&z, .exclusive, 3, D.none);
    core.markRevokedByUrn(&z); // revoke
    _ = try core.control(&x, .set_authorized, "1", 0, D.none); // control
    try core.containByFlooding(&y, D.none); // quarantine set (+ revoke)
    _ = core.clearQuarantine(&y); // quarantine clear
    const bound = [_]Urn{Urn.from("hw:/pci/x/fn0")};
    _ = core.reconcileAfterRestart(&bound); // reconcile quarantine
    _ = core.auditInvariants(); // audit (sound table ⇒ no event)

    // Every site ran; the sink re-entered the core on every one of them.
    try testing.expect(col.count() >= 7);
    try testing.expectEqual(@as(usize, 0), col.lock_violations);
}

// ---------------------------------------------------------------------------
// B1 threaded stress. Mutations on several threads, each publishing through a
// sink that re-enters the core, verdicted by the GPA-backed testing allocator:
// a lock-order regression deadlocks or trips `lock_violations`, and any
// lifetime error in the event payloads (a URN pointing into a freed frame) is
// caught by the allocator's safety accounting at teardown. The full-stack
// version of this race — core mutations against a live subscription registry
// being reaped concurrently — lives in facade_test.zig.
// ---------------------------------------------------------------------------

const StressCtx = struct {
    core: *Core,
    holder: model.ClientId,
    urn_a: Urn,
    urn_b: Urn,
    iters: usize,
};

fn stressMutator(ctx: *StressCtx) void {
    var i: usize = 0;
    while (i < ctx.iters) : (i += 1) {
        const u = if (i % 2 == 0) ctx.urn_a else ctx.urn_b;
        const id = ctx.core.claim(&u, .observe, ctx.holder, D.none) catch continue;
        ctx.core.release(id, ctx.holder, D.none) catch {};
    }
}

fn stressReaper(ctx: *StressCtx) void {
    var i: usize = 0;
    while (i < ctx.iters) : (i += 1) {
        _ = ctx.core.holderDied(ctx.holder);
        _ = ctx.core.liveLeaseCount();
    }
}

test "B1 stress: concurrent claim/release/holderDied emit safely and never publish under the lock" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    try fb.add("hw:/pci/s1/fn0", .claimable, .pcie_function);
    try fb.add("hw:/pci/s2/fn0", .claimable, .pcie_function);
    var core = Core.init(testing.allocator, fb.backend());
    defer core.deinit();

    // The collector's fixed array would overflow long before the run ends;
    // that is fine — it stops recording and keeps policing the lock order,
    // which is what this pin is for.
    var col = EventCollector{};
    wireCollector(&col, &core);

    var c1 = StressCtx{
        .core = &core,
        .holder = 101,
        .urn_a = Urn.from("hw:/pci/s1/fn0"),
        .urn_b = Urn.from("hw:/pci/s2/fn0"),
        .iters = 2000,
    };
    var c2 = StressCtx{
        .core = &core,
        .holder = 202,
        .urn_a = Urn.from("hw:/pci/s2/fn0"),
        .urn_b = Urn.from("hw:/pci/s1/fn0"),
        .iters = 2000,
    };
    var c3 = StressCtx{
        .core = &core,
        .holder = 101,
        .urn_a = c1.urn_a,
        .urn_b = c1.urn_b,
        .iters = 500,
    };

    const t1 = try std.Thread.spawn(.{}, stressMutator, .{&c1});
    const t2 = try std.Thread.spawn(.{}, stressMutator, .{&c2});
    const t3 = try std.Thread.spawn(.{}, stressReaper, .{&c3});
    t1.join();
    t2.join();
    t3.join();

    _ = core.holderDied(101);
    _ = core.holderDied(202);
    try testing.expectEqual(@as(usize, 0), core.liveLeaseCount());
    try testing.expectEqual(@as(usize, 0), col.lock_violations);
    try testing.expect(core.auditInvariants() == null);
}

// ---------------------------------------------------------------------------
// B1-F01 (court finding) — the PUBLISH-LAST ordering, pinned.
//
// The engine publishes an ownership loss only after `backend.release` has
// actually let the hardware go, so "this holder no longer owns it" is true
// at the instant it is heard rather than merely about to be. That ordering
// was documented and implemented but not PINNED: the court's S9 sabotage
// moved `publish` above `backend.release` and every test stayed green.
//
// These two pin the interleaving directly. `OrderRecord` logs both seams
// into one string, so the contract reads as a string: every 'r' before
// every 'p'.
// ---------------------------------------------------------------------------

test "B1-F01 release: the hardware is let go BEFORE the loss is announced" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    try fb.add("hw:/pci/ord/fn0", .claimable, .pcie_function);
    var rec = OrderRecord{};
    var ofb = OpFaultBackend{ .inner = fb.backend(), .order = &rec };
    var core = Core.init(testing.allocator, ofb.backend());
    defer core.deinit();

    const urn = Urn.from("hw:/pci/ord/fn0");
    const id = try core.claim(&urn, .exclusive, 1, D.none);
    core.setEventSink(rec.sink()); // wire AFTER the claim: only the release is logged

    try core.release(id, 1, D.none);

    // Backend release, THEN the event. Not the other way round, and not
    // interleaved — one release, one announcement, in that order.
    try testing.expectEqualStrings("rp", rec.seq());
}

test "B1-F01 holderDied: EVERY reclaimed device is released before ANY loss is announced" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    try fb.add("hw:/pci/ord1/fn0", .claimable, .pcie_function);
    try fb.add("hw:/pci/ord2/fn0", .claimable, .pcie_function);
    var rec = OrderRecord{};
    var ofb = OpFaultBackend{ .inner = fb.backend(), .order = &rec };
    var core = Core.init(testing.allocator, ofb.backend());
    defer core.deinit();

    const a = Urn.from("hw:/pci/ord1/fn0");
    const b = Urn.from("hw:/pci/ord2/fn0");
    _ = try core.claim(&a, .exclusive, 9, D.none);
    _ = try core.claim(&b, .exclusive, 9, D.none);
    core.setEventSink(rec.sink());

    try testing.expectEqual(@as(usize, 2), core.holderDied(9));

    // The batch semantics matter here: holderDied releases the whole set
    // and only then announces the whole set, so a consumer that reacts to
    // the first event already finds every device in the batch free.
    try testing.expectEqualStrings("rrpp", rec.seq());
}
