//! facade_test — THE CONSTELLATION running as one system. Two per-bus workers
//! (PCI + USB) behind one facade, capability-gated, with real-socket liveness
//! driving cross-worker reclamation. This is every proven piece composed:
//! model + kabi + core (×2) + cap + liveness + facade, end to end.

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 Core = @import("mgf_hrb_core").Core;
const liveness = @import("mgf_hrb_liveness");
const facademod = @import("mgf_hrb_facade");
const FakeBackend = @import("mgf_hrb_fake_backend").FakeBackend;
const irqmod = @import("mgf_hrb_irq_monitor");
const lbound = @import("mgf_hrb_linux_bound");

const Urn = model.Urn;
const Err = model.Err;
const Right = cap.Right;
const RightSet = cap.RightSet;

// A test harness that wires two workers (pci, usb) behind a facade, each with
// its own fake backend + core, optionally capability-gated.
const Constellation = struct {
    pci_fb: FakeBackend,
    usb_fb: FakeBackend,
    pci_core: Core,
    usb_core: Core,
    workers: [2]facademod.Worker,
    facade: facademod.Facade,

    fn deinit(self: *Constellation) void {
        self.pci_core.deinit();
        self.usb_core.deinit();
        self.pci_fb.deinit();
        self.usb_fb.deinit();
    }
};

fn buildConstellation(c: *Constellation, alloc: std.mem.Allocator, verifier: ?*cap.CapTable) !void {
    c.pci_fb = FakeBackend.init(alloc);
    c.usb_fb = FakeBackend.init(alloc);
    try c.pci_fb.add("hw:/pci/0000:01:00.0/fn0", .claimable, .pcie_function);
    try c.pci_fb.add("hw:/pci/0000:02:00.0/fn0", .claimable, .pcie_function);
    try c.usb_fb.add("hw:/usb/bus1/dev4/if0", .claimable, .usb_interface);

    if (verifier) |v| {
        c.pci_core = Core.initWithCaps(alloc, c.pci_fb.backend(), v);
        c.usb_core = Core.initWithCaps(alloc, c.usb_fb.backend(), v);
    } else {
        c.pci_core = Core.init(alloc, c.pci_fb.backend());
        c.usb_core = Core.init(alloc, c.usb_fb.backend());
    }
    c.workers = .{
        .{ .scope_prefix = "hw:/pci/", .core = &c.pci_core },
        .{ .scope_prefix = "hw:/usb/", .core = &c.usb_core },
    };
    if (verifier) |v| {
        c.facade = facademod.Facade.initWithCaps(&c.workers, v);
    } else {
        c.facade = facademod.Facade.init(&c.workers);
    }
}

test "constellation: facade routes a claim to the OWNING worker by scope" {
    var c: Constellation = undefined;
    try buildConstellation(&c, testing.allocator, null);
    defer c.deinit();

    const pci = Urn.from("hw:/pci/0000:01:00.0/fn0");
    const usb = Urn.from("hw:/usb/bus1/dev4/if0");

    _ = try c.facade.claim(0, &pci, .exclusive, 1, kabi.Deadline.none); // routed to pci worker
    _ = try c.facade.claim(0, &usb, .exclusive, 1, kabi.Deadline.none); // routed to usb worker

    // each worker holds exactly its own lease — routing landed correctly
    try testing.expectEqual(@as(usize, 1), c.pci_core.liveLeaseCount());
    try testing.expectEqual(@as(usize, 1), c.usb_core.liveLeaseCount());
    try testing.expectEqual(@as(usize, 2), c.facade.totalLeases());
}

test "constellation: enumerate fans out across workers and merges (Part 7.2)" {
    var c: Constellation = undefined;
    try buildConstellation(&c, testing.allocator, null);
    defer c.deinit();

    const Collector = struct {
        items: std.ArrayListUnmanaged(model.Resource) = .empty,
        alloc: std.mem.Allocator,
        fn push(ctx: *anyopaque, r: model.Resource) void {
            const self: *@This() = @ptrCast(@alignCast(ctx));
            self.items.append(self.alloc, r) catch {};
        }
    };
    var col = Collector{ .alloc = testing.allocator };
    defer col.items.deinit(testing.allocator);
    const sink = kabi.FactSink{ .ctx = &col, .push = Collector.push };

    // "hw:/**" fans out to BOTH workers → 2 pci + 1 usb = 3 devices merged
    try c.facade.enumerate("hw:/**", &sink, kabi.Deadline.none);
    try testing.expectEqual(@as(usize, 3), col.items.items.len);

    // "hw:/usb/**" reaches ONLY the usb worker → 1 device
    col.items.clearRetainingCapacity();
    try c.facade.enumerate("hw:/usb/**", &sink, kabi.Deadline.none);
    try testing.expectEqual(@as(usize, 1), col.items.items.len);
}

test "constellation FAILURE ISOLATION: a client's death reclaims across workers, others untouched" {
    var c: Constellation = undefined;
    try buildConstellation(&c, testing.allocator, null);
    defer c.deinit();

    const pci = Urn.from("hw:/pci/0000:01:00.0/fn0");
    const usb = Urn.from("hw:/usb/bus1/dev4/if0");
    const pci2 = Urn.from("hw:/pci/0000:02:00.0/fn0");

    // client 7 holds a PCI and a USB device (spanning two workers);
    // client 9 holds another PCI device.
    _ = try c.facade.claim(0, &pci, .exclusive, 7, kabi.Deadline.none);
    _ = try c.facade.claim(0, &usb, .exclusive, 7, kabi.Deadline.none);
    _ = try c.facade.claim(0, &pci2, .exclusive, 9, kabi.Deadline.none);
    try testing.expectEqual(@as(usize, 3), c.facade.totalLeases());

    // client 7 dies — facade tells every worker to reclaim 7's leases
    const reclaimed = c.facade.holderDied(7);
    try testing.expectEqual(@as(usize, 2), reclaimed); // both of 7's leases, across two workers

    // client 9's lease is UNTOUCHED — failure isolation across the constellation
    try testing.expectEqual(@as(usize, 1), c.facade.totalLeases());
    try testing.expect(c.pci_core.stateOf(&pci2) == .claimed);
    // and 7's devices are safe-reset and re-claimable
    try testing.expect(c.pci_fb.isSafe("hw:/pci/0000:01:00.0/fn0"));
    try testing.expect(c.usb_fb.isSafe("hw:/usb/bus1/dev4/if0"));
}

test "constellation + caps: capability-gated claim routed and enforced end-to-end" {
    var ct = cap.CapTable.init(testing.allocator);
    defer ct.deinit();
    var c: Constellation = undefined;
    try buildConstellation(&c, testing.allocator, &ct);
    defer c.deinit();

    // a tenant with exclusive on USB ONLY
    const usb_cap = try ct.mint(.{
        .scope = Urn.from("hw:/usb/**"),
        .rights = RightSet.of(&.{ .observe, .claim_exclusive }),
    });
    const usb = Urn.from("hw:/usb/bus1/dev4/if0");
    const pci = Urn.from("hw:/pci/0000:01:00.0/fn0");

    // permitted: USB claim with the USB cap, routed to the usb worker
    _ = try c.facade.claim(usb_cap, &usb, .exclusive, 1, kabi.Deadline.none);
    try testing.expectEqual(@as(usize, 1), c.usb_core.liveLeaseCount());

    // REFUSED: same cap cannot claim PCI (out of scope) — caught before the
    // pci worker touches anything. Capability + routing + lease engine, composed.
    try testing.expectError(Err.NotPermitted, c.facade.claim(usb_cap, &pci, .exclusive, 1, kabi.Deadline.none));
    try testing.expectEqual(@as(usize, 0), c.pci_core.liveLeaseCount());
}

test "constellation + REAL liveness: a closed socket reclaims across the whole system" {
    var c: Constellation = undefined;
    try buildConstellation(&c, testing.allocator, null);
    defer c.deinit();

    // wire the liveness monitor's death signal into the FACADE (cross-worker)
    const FacadeSink = struct {
        facade: *facademod.Facade,
        fn onDeath(ctx: *anyopaque, who: model.ClientId) void {
            const self: *@This() = @ptrCast(@alignCast(ctx));
            _ = self.facade.holderDied(who);
        }
    };
    var fsink = FacadeSink{ .facade = &c.facade };
    const src = liveness.LivenessSource{ .ctx = &fsink, .on_death = FacadeSink.onDeath };
    var mon = liveness.LivenessMonitor.init(testing.allocator, src);
    defer mon.deinit();

    const pair = try liveness.seqpacketPair();
    try mon.register(pair.broker, 7);

    // client 7 claims across both buses, then "dies"
    _ = try c.facade.claim(0, &Urn.from("hw:/pci/0000:01:00.0/fn0"), .exclusive, 7, kabi.Deadline.none);
    _ = try c.facade.claim(0, &Urn.from("hw:/usb/bus1/dev4/if0"), .exclusive, 7, kabi.Deadline.none);
    try testing.expectEqual(@as(usize, 2), c.facade.totalLeases());

    liveness.closeFd(pair.client); // the client process dies
    const reclaimed = mon.pollConnections(); // kernel reports it; facade reclaims
    try testing.expectEqual(@as(usize, 1), reclaimed); // one client gone
    try testing.expectEqual(@as(usize, 0), c.facade.totalLeases()); // ALL its leases gone, both buses

    liveness.closeFd(pair.broker);
    std.debug.print("\n  [constellation] real client death reclaimed leases across BOTH workers\n", .{});
}

// === FEEDBACK SDK-03 — Facade.listLeases cross-worker aggregation =========

const core_mod = @import("mgf_hrb_core");

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

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

test "constellation SDK-03: listLeases merges across workers (Part 7.2)" {
    var c: Constellation = undefined;
    try buildConstellation(&c, testing.allocator, null);
    defer c.deinit();

    const pci = Urn.from("hw:/pci/0000:01:00.0/fn0");
    const usb = Urn.from("hw:/usb/bus1/dev4/if0");
    _ = try c.facade.claim(0, &pci, .exclusive, 1, kabi.Deadline.none);
    _ = try c.facade.claim(0, &usb, .observe, 2, kabi.Deadline.none);

    // Broad scope — both workers contribute their lease.
    var col = FacadeRecordCollector{ .alloc = testing.allocator };
    defer col.deinit();
    const s = col.sink();
    c.facade.listLeases("hw:/**", &s);

    try testing.expectEqual(@as(usize, 2), col.records.items.len);
    // Verify both holders are present (order across workers is not guaranteed).
    var saw_pci_holder_1 = false;
    var saw_usb_holder_2 = false;
    for (col.records.items) |r| {
        if (r.holder == 1 and std.mem.startsWith(u8, r.urn.slice(), "hw:/pci/")) {
            saw_pci_holder_1 = true;
            try testing.expectEqual(model.ClaimMode.exclusive, r.mode);
        }
        if (r.holder == 2 and std.mem.startsWith(u8, r.urn.slice(), "hw:/usb/")) {
            saw_usb_holder_2 = true;
            try testing.expectEqual(model.ClaimMode.observe, r.mode);
        }
    }
    try testing.expect(saw_pci_holder_1);
    try testing.expect(saw_usb_holder_2);
}

test "constellation SDK-03: per-bus scope routes to only that worker" {
    var c: Constellation = undefined;
    try buildConstellation(&c, testing.allocator, null);
    defer c.deinit();

    _ = try c.facade.claim(0, &Urn.from("hw:/pci/0000:01:00.0/fn0"), .exclusive, 1, kabi.Deadline.none);
    _ = try c.facade.claim(0, &Urn.from("hw:/usb/bus1/dev4/if0"), .exclusive, 2, kabi.Deadline.none);

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

    try testing.expectEqual(@as(usize, 1), col.records.items.len);
    try testing.expectEqual(@as(model.ClientId, 2), col.records.items[0].holder);
    try testing.expect(std.mem.startsWith(u8, col.records.items[0].urn.slice(), "hw:/usb/"));
}

test "constellation SDK-03: empty constellation yields zero records" {
    var c: Constellation = undefined;
    try buildConstellation(&c, testing.allocator, null);
    defer c.deinit();
    // No claims made — both workers are empty.

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

// =============================================================================
// R-T1-11A (ROADMAP / survivability §3.6) — capability-filtered enumeration.
// The S3 isolation gap: pre-R-T1-11A, `enumerate` returned all resources
// regardless of caller scope — tenant A could observe tenant B's URNs.
// Post-R-T1-11A, when the caller presents a non-zero cap_id on `list`, the
// broker intersects the request with the cap's scope before emission.
//
// These tests pin the facade surface (`capPermitsNaming` / `usesCapFilter`).
// The server-side `ListCollector` integration is exercised end-to-end via
// the Python conformance suite once the SDK passes cap_id on list().
// =============================================================================

test "R-T1-11A: usesCapFilter is false when no verifier (no cap layer)" {
    var c: Constellation = undefined;
    try buildConstellation(&c, testing.allocator, null);
    defer c.deinit();
    try testing.expect(!c.facade.usesCapFilter(0));
    // even a non-zero cap_id with no verifier means "no filter applies"
    // (the verifier is the only authority — without it the request is
    // structurally pre-cap-era; preserves legacy compat)
    try testing.expect(!c.facade.usesCapFilter(99));
}

test "R-T1-11A: usesCapFilter requires BOTH verifier and non-zero cap_id" {
    var ct = cap.CapTable.init(testing.allocator);
    defer ct.deinit();
    var c: Constellation = undefined;
    try buildConstellation(&c, testing.allocator, &ct);
    defer c.deinit();
    // verifier wired but cap_id 0 (legacy client) → no filter
    try testing.expect(!c.facade.usesCapFilter(0));
    // verifier wired AND cap_id non-zero → filter applies
    try testing.expect(c.facade.usesCapFilter(42));
}

test "R-T1-11A: capPermitsNaming filters by cap scope (in-scope and out-of-scope)" {
    var ct = cap.CapTable.init(testing.allocator);
    defer ct.deinit();
    var c: Constellation = undefined;
    try buildConstellation(&c, testing.allocator, &ct);
    defer c.deinit();

    const usb_cap = try ct.mint(.{
        .scope = Urn.from("hw:/usb/**"),
        .rights = RightSet.of(&.{.observe}),
    });
    const usb_urn = Urn.from("hw:/usb/bus1/dev4/if0");
    const pci_urn = Urn.from("hw:/pci/0000:01:00.0/fn0");

    // USB urn within USB cap scope → permitted to name
    try testing.expect(c.facade.capPermitsNaming(usb_cap, &usb_urn));
    // PCI urn outside USB cap scope → NOT permitted to name
    // (this is the S3 isolation property — the holder of the USB cap
    // cannot even *observe the existence* of PCI URNs)
    try testing.expect(!c.facade.capPermitsNaming(usb_cap, &pci_urn));
}

test "R-T1-11A: capPermitsNaming refuses an unknown cap_id (forgery probe)" {
    var ct = cap.CapTable.init(testing.allocator);
    defer ct.deinit();
    var c: Constellation = undefined;
    try buildConstellation(&c, testing.allocator, &ct);
    defer c.deinit();

    const some_urn = Urn.from("hw:/usb/bus1/dev4/if0");
    // 0xdeadbeef is not a minted cap_id; an attacker who guesses an id
    // can't enumerate against it. Same behavior as `permitsClaim` on
    // unknown ids — false, never panic.
    try testing.expect(!c.facade.capPermitsNaming(0xdead_beef, &some_urn));
}

test "R-T1-11A: capPermitsNaming with no verifier returns true (legacy compat)" {
    // No verifier ⇒ no cap layer ⇒ no filter ⇒ everything is permitted
    // to name (pre-cap-era behavior, preserved). This is the path the
    // ListCollector takes when `usesCapFilter` returned false.
    var c: Constellation = undefined;
    try buildConstellation(&c, testing.allocator, null);
    defer c.deinit();
    const usb_urn = Urn.from("hw:/usb/bus1/dev4/if0");
    try testing.expect(c.facade.capPermitsNaming(99, &usb_urn));
}

test "R-T1-11A: CapTable.permitsNaming pins the same shape at the lower layer" {
    var ct = cap.CapTable.init(testing.allocator);
    defer ct.deinit();
    const usb_cap = try ct.mint(.{
        .scope = Urn.from("hw:/usb/**"),
        .rights = RightSet.of(&.{.observe}),
    });
    // In-scope
    try testing.expect(ct.permitsNaming(usb_cap, &Urn.from("hw:/usb/bus1/dev4/if0")));
    // Out-of-scope
    try testing.expect(!ct.permitsNaming(usb_cap, &Urn.from("hw:/pci/0000:01:00.0/fn0")));
    // Unknown id
    try testing.expect(!ct.permitsNaming(0xdead_beef, &Urn.from("hw:/usb/bus1/dev4/if0")));
    // Wire sentinel (id 0)
    try testing.expect(!ct.permitsNaming(0, &Urn.from("hw:/usb/bus1/dev4/if0")));
}

// ===========================================================================
// R-T1-8-RESTART-WIRING — the broker-wide enumerate → reconcileAfterRestart
// wiring (the live side of the Tier-1 #8 recovery contract). core_test pins
// the per-core mechanism; this pins the facade fan-out across workers.
// ===========================================================================

test "#8 reconcile wiring: present-but-unclaimed across workers → quarantined; live lease left alone" {
    var c: Constellation = undefined;
    try buildConstellation(&c, testing.allocator, null);
    defer c.deinit();

    // 3 devices present (2 pci + 1 usb). A live client holds ONE of them —
    // the rest are orphans after a (simulated) restart.
    const held = Urn.from("hw:/pci/0000:01:00.0/fn0");
    const orphan_pci = Urn.from("hw:/pci/0000:02:00.0/fn0");
    const orphan_usb = Urn.from("hw:/usb/bus1/dev4/if0");
    _ = try c.facade.claim(0, &held, .exclusive, 7, kabi.Deadline.none);

    // Broker-wide reconcile: enumerate every worker, quarantine the orphans.
    const report = c.facade.reconcileAfterRestart("hw:/**", null, kabi.Deadline.none);
    try testing.expectEqual(@as(usize, 3), report.scanned); // all 3 present devices scanned
    try testing.expectEqual(@as(usize, 2), report.quarantined); // the 2 orphans
    try testing.expect(!report.truncated);

    // The live lease is untouched; both orphans (spanning two workers) are quarantined.
    try testing.expect(c.pci_core.quarantineStatus(&held) == null);
    try testing.expect(c.pci_core.quarantineStatus(&orphan_pci) != null);
    try testing.expect(c.usb_core.quarantineStatus(&orphan_usb) != null);

    // Idempotent: a second reconcile quarantines nothing new.
    const again = c.facade.reconcileAfterRestart("hw:/**", null, kabi.Deadline.none);
    try testing.expectEqual(@as(usize, 0), again.quarantined);
}

test "#8 reconcile wiring: a scoped reconcile only touches the matching worker" {
    var c: Constellation = undefined;
    try buildConstellation(&c, testing.allocator, null);
    defer c.deinit();

    // Reconcile ONLY the usb subtree — the pci worker must be left entirely alone
    // (its devices neither scanned nor quarantined).
    const report = c.facade.reconcileAfterRestart("hw:/usb/**", null, kabi.Deadline.none);
    try testing.expectEqual(@as(usize, 1), report.scanned); // only the 1 usb device
    try testing.expectEqual(@as(usize, 1), report.quarantined);
    try testing.expect(c.usb_core.quarantineStatus(&Urn.from("hw:/usb/bus1/dev4/if0")) != null);
    // PCI devices were out of scope — untouched, still claimable.
    try testing.expect(c.pci_core.quarantineStatus(&Urn.from("hw:/pci/0000:01:00.0/fn0")) == null);
    try testing.expect(c.pci_core.quarantineStatus(&Urn.from("hw:/pci/0000:02:00.0/fn0")) == null);
}

// ===========================================================================
// D7 — interrupt-rate containment scan (Tier-2 defense-in-depth). irq_monitor
// pins the rate POLICY in isolation; this pins the facade scan end-to-end:
// granted device floods → revoked + quarantined; calm devices untouched.
// ===========================================================================

test "D7 scan: a flooding granted device is revoked + quarantined; calm ones untouched" {
    var c: Constellation = undefined;
    try buildConstellation(&c, testing.allocator, null);
    defer c.deinit();

    const flooder = Urn.from("hw:/pci/0000:01:00.0/fn0");
    const calm = Urn.from("hw:/pci/0000:02:00.0/fn0");
    _ = try c.facade.claim(0, &flooder, .exclusive, 1, kabi.Deadline.none);
    _ = try c.facade.claim(0, &calm, .exclusive, 2, kabi.Deadline.none);

    var monitor = irqmod.IrqMonitor.init(testing.allocator, 1000); // ceiling 1000 IRQ/s
    defer monitor.deinit();

    // Injected counter source: returns the current count for each device.
    const Counts = struct {
        flooder: Urn,
        calm: Urn,
        f: u64 = 0,
        cc: u64 = 0,
        fn get(ctx: *anyopaque, urn: *const Urn) ?u64 {
            const s: *@This() = @ptrCast(@alignCast(ctx));
            if (urn.eql(&s.flooder)) return s.f;
            if (urn.eql(&s.calm)) return s.cc;
            return null;
        }
    };
    var counts = Counts{ .flooder = flooder, .calm = calm };
    const source = irqmod.IrqCounterSource{ .ctx = &counts, .get = Counts.get };

    // Scan 1 (t=1000ms) — both devices baseline; nothing contained yet.
    const r1 = c.facade.scanInterruptRates(&monitor, source, 1000, kabi.Deadline.none);
    try testing.expectEqual(@as(usize, 2), r1.scanned);
    try testing.expectEqual(@as(usize, 0), r1.contained);

    // Counts advance over 100ms: flooder +1_000_000 (10M/s ≫ ceiling); calm +50 (500/s).
    counts.f = 1_000_000;
    counts.cc = 50;
    const r2 = c.facade.scanInterruptRates(&monitor, source, 1100, kabi.Deadline.none);
    try testing.expectEqual(@as(usize, 2), r2.scanned); // both still leased at scan start
    try testing.expectEqual(@as(usize, 1), r2.contained); // only the flooder

    // The flooder is quarantined (lease torn down); the calm device is untouched.
    try testing.expect(c.pci_core.quarantineStatus(&flooder) != null);
    try testing.expect(c.pci_core.quarantineStatus(&calm) == null);
    // Re-claiming the contained device is refused until an operator recovers it.
    try testing.expectError(Err.Unavailable, c.facade.claim(0, &flooder, .exclusive, 9, kabi.Deadline.none));
}

// ===========================================================================
// R-T1-8 (b) — bound-classification precision for reconcile. linux_bound pins
// the classifier; this pins that the facade's reconcile, given a bound source,
// quarantines ONLY genuinely hardware-bound orphans and leaves idle-free /
// host-used devices alone (the over-quarantine the present-set would cause).
// ===========================================================================

test "#8 reconcile (b): a bound source quarantines only orphans, sparing host-used devices" {
    var c: Constellation = undefined;
    try buildConstellation(&c, testing.allocator, null);
    defer c.deinit();

    // Injected bound source: pci 0000:02:00.0 is host-used (NOT an orphan);
    // everything else (the other pci + the usb device) is bound.
    const FakeBound = struct {
        fn isBound(ctx: *anyopaque, urn: *const Urn) bool {
            _ = ctx;
            return !std.mem.eql(u8, urn.slice(), "hw:/pci/0000:02:00.0/fn0");
        }
    };
    var bctx: u8 = 0;
    const bound = lbound.BoundSource{ .ctx = &bctx, .is_bound = FakeBound.isBound };

    // No live leases — every present device is unclaimed. With the bound filter,
    // only the hardware-bound ones are quarantined; the host-used one is spared.
    const report = c.facade.reconcileAfterRestart("hw:/**", bound, kabi.Deadline.none);
    try testing.expectEqual(@as(usize, 2), report.scanned); // bound-filtered: 01:00.0 + usb (02:00.0 excluded)
    try testing.expectEqual(@as(usize, 2), report.quarantined);

    try testing.expect(c.pci_core.quarantineStatus(&Urn.from("hw:/pci/0000:01:00.0/fn0")) != null); // orphan → quarantined
    try testing.expect(c.pci_core.quarantineStatus(&Urn.from("hw:/pci/0000:02:00.0/fn0")) == null); // host-used → untouched
    try testing.expect(c.usb_core.quarantineStatus(&Urn.from("hw:/usb/bus1/dev4/if0")) != null); // conservative include

    // Contrast: the SAME reconcile with NO bound source (null) is the prior
    // present-set behaviour — it would quarantine the host-used device too.
    var c2: Constellation = undefined;
    try buildConstellation(&c2, testing.allocator, null);
    defer c2.deinit();
    const r2 = c2.facade.reconcileAfterRestart("hw:/**", null, kabi.Deadline.none);
    try testing.expectEqual(@as(usize, 3), r2.quarantined); // all present-and-unclaimed
}

// ---------------------------------------------------------------------------
// M-B B1 — the wiring, end to end. `Facade.init` points every worker Core's
// event sink at `subscription.pushFanout`, so a mutation made through the
// facade lands in a real subscriber's ring with no polling anywhere in the
// path. Before B1 the ONLY caller of pushFanout was the drain_events
// formatter, so a lease change reached nobody until somebody polled.
// ---------------------------------------------------------------------------

const sub = @import("mgf_hrb_subscription");

fn subscribeAll(peer: u64, id: []const u8, scope: []const u8) !void {
    const arena = std.heap.ArenaAllocator.init(testing.allocator);
    _ = try sub.register(peer, id, scope, .{ .matches_all = {} }, arena);
}

test "B1 wiring: a facade-routed claim reaches a live subscription's ring" {
    sub.init(testing.allocator);
    defer sub.deinit();

    var c: Constellation = undefined;
    try buildConstellation(&c, testing.allocator, null);
    defer c.deinit();
    try subscribeAll(1, "s1", "hw:/pci/**");

    const pci = Urn.from("hw:/pci/0000:01:00.0/fn0");
    const usb = Urn.from("hw:/usb/bus1/dev4/if0");
    const lease = try c.facade.claim(0, &pci, .exclusive, 77, kabi.Deadline.none);
    _ = try c.facade.claim(0, &usb, .exclusive, 77, kabi.Deadline.none); // out of scope
    try c.facade.release(&pci, lease, 77, kabi.Deadline.none);

    var buf: [8]model.Event = undefined;
    const n = try sub.drainSubscription(1, "s1", &buf);
    // The USB claim is filtered out by the subscription's scope; the PCI
    // grant and its release are both delivered, in order.
    try testing.expectEqual(@as(usize, 2), n);
    try testing.expect(buf[0] == .ownership_changed);
    try testing.expectEqual(@as(model.ClientId, 77), buf[0].ownership_changed.new.?);
    try testing.expect(buf[1] == .ownership_changed);
    try testing.expect(buf[1].ownership_changed.new == null);
    try testing.expectEqual(@as(model.ClientId, 77), buf[1].ownership_changed.old.?);
}

test "B1 wiring: a client's death is announced to every matching subscriber" {
    sub.init(testing.allocator);
    defer sub.deinit();

    var c: Constellation = undefined;
    try buildConstellation(&c, testing.allocator, null);
    defer c.deinit();
    // TWO subscribers on two peers — the stealing class this milestone kills
    // starts here: both must see the same event, not race for it.
    try subscribeAll(1, "a", "hw:/**");
    try subscribeAll(2, "b", "hw:/**");

    const pci = Urn.from("hw:/pci/0000:01:00.0/fn0");
    const usb = Urn.from("hw:/usb/bus1/dev4/if0");
    _ = try c.facade.claim(0, &pci, .exclusive, 9, kabi.Deadline.none);
    _ = try c.facade.claim(0, &usb, .exclusive, 9, kabi.Deadline.none);
    try testing.expectEqual(@as(usize, 2), c.facade.holderDied(9));

    var buf: [8]model.Event = undefined;
    // 2 grants + 2 reclamations, delivered in full to BOTH peers.
    try testing.expectEqual(@as(usize, 4), try sub.drainSubscription(1, "a", &buf));
    try testing.expectEqual(@as(usize, 4), try sub.drainSubscription(2, "b", &buf));
}

// ---------------------------------------------------------------------------
// B1 full-stack stress — the shape subscription_test.zig's R2-A3 pin
// established, now driven from the lease engine instead of a synthetic event:
// real mutations on one thread, subscription register/reap churn on another,
// direct fan-out on a third. The GPA-backed testing allocator is the verdict
// (any use-after-free, double-free, or leak in the fan-out's deferred-free
// path fails the test at teardown); the mutation thread additionally proves
// that publishing from inside a mutation never deadlocks against the reaper.
// ---------------------------------------------------------------------------

const StressState = struct {
    facade: *facademod.Facade,
    iters: usize,
};

fn stressMutations(st: *StressState) void {
    const pci = Urn.from("hw:/pci/0000:01:00.0/fn0");
    const usb = Urn.from("hw:/usb/bus1/dev4/if0");
    var i: usize = 0;
    while (i < st.iters) : (i += 1) {
        const u = if (i % 2 == 0) pci else usb;
        const id = st.facade.claim(0, &u, .observe, 55, kabi.Deadline.none) catch continue;
        st.facade.release(&u, id, 55, kabi.Deadline.none) catch {};
        if (i % 16 == 0) _ = st.facade.holderDied(55);
    }
}

fn stressChurn(iters: usize) void {
    var i: usize = 0;
    while (i < iters) : (i += 1) {
        const arena = std.heap.ArenaAllocator.init(testing.allocator);
        _ = sub.register(42, "s", "hw:/**", .{ .matches_all = {} }, arena) catch continue;
        sub.reapPeer(42); // may unlink while a fan-out eval holds a ref
    }
}

fn stressFanout(iters: usize) void {
    var i: usize = 0;
    while (i < iters) : (i += 1) {
        sub.pushFanout(
            .{ .added = .{ .urn = Urn.from("hw:/pci/0000:02:00.0/fn0") } },
            .{ .ctx = null, .get = null },
        );
    }
}

test "B1 stress: core mutations x subscription churn x fan-out is UAF/leak-free" {
    sub.init(testing.allocator);
    defer sub.deinit();

    var c: Constellation = undefined;
    try buildConstellation(&c, testing.allocator, null);
    defer c.deinit();

    var st = StressState{ .facade = &c.facade, .iters = 3000 };
    const t_mut = try std.Thread.spawn(.{}, stressMutations, .{&st});
    const t_churn = try std.Thread.spawn(.{}, stressChurn, .{3000});
    const t_fan = try std.Thread.spawn(.{}, stressFanout, .{3000});
    t_mut.join();
    t_churn.join();
    t_fan.join();

    sub.reapPeer(42); // reap any survivor so deinit sees a clean registry
    try testing.expectEqual(@as(usize, 0), sub.count());
    _ = c.facade.holderDied(55);
    try testing.expectEqual(@as(usize, 0), c.facade.totalLeases());
    try testing.expect(c.pci_core.auditInvariants() == null);
    try testing.expect(c.usb_core.auditInvariants() == null);
}
