//! cap_test — proves the capability model's invariants (Part 4) in code:
//! attenuation only ever shrinks, rights are segregated, `raw` is its own
//! right, and the core enforces capabilities on the grant path.

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 FakeBackend = @import("mgf_hrb_fake_backend").FakeBackend;

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

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 "cap: a capability permits exactly its scope, rights, and mode ceiling" {
    var ct = cap.CapTable.init(testing.allocator);
    defer ct.deinit();
    const id = try ct.mint(.{
        .scope = Urn.from("hw:/usb/**"),
        .rights = RightSet.of(&.{ .observe, .claim_exclusive }),
        .mode_ceiling = .exclusive,
    });
    const usb = Urn.from("hw:/usb/bus1/dev4/if0");
    const pci = Urn.from("hw:/pci/0000:01:00.0/fn0");

    try testing.expect(ct.permitsClaim(id, &usb, .exclusive)); // in scope, has right
    try testing.expect(!ct.permitsClaim(id, &pci, .exclusive)); // OUT of scope
    try testing.expect(ct.permitsClaim(id, &usb, .observe)); // observe ⊆ rights & ceiling
}

test "cap attenuation SHRINKS scope: child confined to a sub-tree" {
    var ct = cap.CapTable.init(testing.allocator);
    defer ct.deinit();
    const parent = try ct.mint(.{
        .scope = Urn.from("hw:/usb/**"),
        .rights = RightSet.of(&.{ .observe, .claim_exclusive, .raw }),
    });
    // narrow to one device
    const child = try ct.attenuate(parent, .{ .scope = "hw:/usb/bus1/dev4/**" });
    const dev4 = Urn.from("hw:/usb/bus1/dev4/if0");
    const dev5 = Urn.from("hw:/usb/bus1/dev5/if0");

    try testing.expect(ct.permitsClaim(child, &dev4, .exclusive)); // inside child scope
    try testing.expect(!ct.permitsClaim(child, &dev5, .exclusive)); // outside child scope
    // parent still sees both
    try testing.expect(ct.permitsClaim(parent, &dev5, .exclusive));
}

test "cap attenuation SHRINKS rights: drop everything but observe" {
    var ct = cap.CapTable.init(testing.allocator);
    defer ct.deinit();
    const parent = try ct.mint(.{
        .scope = Urn.from("hw:/**"),
        .rights = RightSet.of(&.{ .observe, .claim_exclusive, .raw }),
    });
    const child = try ct.attenuate(parent, .{ .rights = RightSet.of(&.{.observe}) });
    const dev = Urn.from("hw:/pci/0000:01:00.0/fn0");

    try testing.expect(ct.permitsClaim(child, &dev, .observe)); // observe kept
    try testing.expect(!ct.permitsClaim(child, &dev, .exclusive)); // claim dropped
    try testing.expect(!ct.permitsRaw(child, &dev)); // raw dropped
    try testing.expect(ct.permitsRaw(parent, &dev)); // parent still has raw
}

test "cap attenuation REFUSES to widen rights (the monotone invariant)" {
    var ct = cap.CapTable.init(testing.allocator);
    defer ct.deinit();
    const parent = try ct.mint(.{
        .scope = Urn.from("hw:/usb/**"),
        .rights = RightSet.of(&.{.observe}), // observe ONLY
    });
    // attempt to add claim_exclusive — a WIDENING — must be refused
    try testing.expectError(Err.NotPermitted, ct.attenuate(parent, .{
        .rights = RightSet.of(&.{ .observe, .claim_exclusive }),
    }));
}

test "cap attenuation REFUSES to widen scope (escape the parent sub-tree)" {
    var ct = cap.CapTable.init(testing.allocator);
    defer ct.deinit();
    const parent = try ct.mint(.{
        .scope = Urn.from("hw:/usb/**"), // USB only
        .rights = RightSet.of(&.{ .observe, .claim_exclusive }),
    });
    // attempt to widen scope to all hardware — must be refused
    try testing.expectError(Err.NotPermitted, ct.attenuate(parent, .{ .scope = "hw:/**" }));
    // and crossing to a sibling bus is also refused
    try testing.expectError(Err.NotPermitted, ct.attenuate(parent, .{ .scope = "hw:/pci/**" }));
}

test "cap attenuation REFUSES to raise the mode ceiling" {
    var ct = cap.CapTable.init(testing.allocator);
    defer ct.deinit();
    const parent = try ct.mint(.{
        .scope = Urn.from("hw:/**"),
        .rights = RightSet.of(&.{ .observe, .claim_shared, .claim_exclusive }),
        .mode_ceiling = .shared_rw, // may claim, but never exclusively
    });
    const dev = Urn.from("hw:/pci/0000:01:00.0/fn0");
    // even though the right exists, the ceiling forbids exclusive
    try testing.expect(!ct.permitsClaim(parent, &dev, .exclusive));
    try testing.expect(ct.permitsClaim(parent, &dev, .shared_rw));
    // attenuating to RAISE the ceiling to exclusive must be refused
    try testing.expectError(Err.NotPermitted, ct.attenuate(parent, .{ .mode_ceiling = .exclusive }));
    // attenuating to LOWER the ceiling to observe is fine
    _ = try ct.attenuate(parent, .{ .mode_ceiling = .observe });
}

test "cap: `raw` is a SEPARATE right from claim (different trust levels)" {
    var ct = cap.CapTable.init(testing.allocator);
    defer ct.deinit();
    // a capability that can control a device but NOT poke its registers
    const id = try ct.mint(.{
        .scope = Urn.from("hw:/pci/**"),
        .rights = RightSet.of(&.{ .observe, .claim_exclusive }), // NO raw
    });
    const dev = Urn.from("hw:/pci/0000:01:00.0/fn0");
    try testing.expect(ct.permitsClaim(id, &dev, .exclusive)); // may control
    try testing.expect(!ct.permitsRaw(id, &dev)); // may NOT go raw
}

test "core+cap end-to-end: capability-checked claim through the lease engine" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    var ct = cap.CapTable.init(testing.allocator);
    defer ct.deinit();
    var core = Core.initWithCaps(testing.allocator, try seeded(&fb), &ct);
    defer core.deinit();

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

    // permitted: claim USB with the USB cap
    const lease = try core.claimWithCap(usb_cap, null, &usb, .exclusive, 1, kabi.Deadline.none);
    try testing.expectEqual(@as(usize, 1), core.liveLeaseCount());
    // permitted: raw on the held USB lease (cap has `raw`)
    _ = try core.rawWithCap(usb_cap, null, lease, 1, kabi.Deadline.none);

    // REFUSED: same cap cannot claim PCI (out of scope) — no hardware touched
    try testing.expectError(Err.NotPermitted, core.claimWithCap(usb_cap, null, &pci, .exclusive, 1, kabi.Deadline.none));
    try testing.expectEqual(@as(usize, 1), core.liveLeaseCount()); // unchanged
    try testing.expect(fb.isSafe("hw:/pci/0000:01:00.0/fn0")); // PCI untouched

    try core.release(lease, 1, kabi.Deadline.none);
}

test "core+cap: a claim-only capability is refused `raw` even when it holds the lease" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    var ct = cap.CapTable.init(testing.allocator);
    defer ct.deinit();
    var core = Core.initWithCaps(testing.allocator, try seeded(&fb), &ct);
    defer core.deinit();

    // can claim, but has NO raw right
    const claim_only = try ct.mint(.{
        .scope = Urn.from("hw:/pci/**"),
        .rights = RightSet.of(&.{ .observe, .claim_exclusive }),
    });
    const pci = Urn.from("hw:/pci/0000:01:00.0/fn0");

    const lease = try core.claimWithCap(claim_only, null, &pci, .exclusive, 1, kabi.Deadline.none);
    // holds the lease, but the cap lacks `raw` → raw refused (Part 4.3)
    try testing.expectError(Err.NotPermitted, core.rawWithCap(claim_only, null, lease, 1, kabi.Deadline.none));
    try core.release(lease, 1, kabi.Deadline.none);
}

// === Part 12 §3.3 Tier-0 #2 — connection-bound capabilities ================

test "cap binding: an UNBOUND cap accepts any peer (back-compat)" {
    var ct = cap.CapTable.init(testing.allocator);
    defer ct.deinit();
    const id = try ct.mint(.{
        .scope = Urn.from("hw:/**"),
        .rights = RightSet.of(&.{.claim_exclusive}),
    });
    const urn = Urn.from("hw:/pci/0000:01:00.0/fn0");
    const alice = cap.PeerCred{ .uid = 1000, .pid = 100 };
    const bob = cap.PeerCred{ .uid = 1001, .pid = 200 };
    // Both peers accepted while the cap is unbound — same as the
    // legacy non-peer-aware check (no regression for callers that
    // don't yet supply a peer).
    try testing.expect(ct.permitsClaimFromPeer(id, &urn, .exclusive, alice));
    try testing.expect(ct.permitsClaimFromPeer(id, &urn, .exclusive, bob));
}

test "cap binding: a BOUND cap accepts only the bound peer (U4 confusion closure)" {
    var ct = cap.CapTable.init(testing.allocator);
    defer ct.deinit();
    const id = try ct.mint(.{
        .scope = Urn.from("hw:/**"),
        .rights = RightSet.of(&.{ .claim_exclusive, .raw, .detach_driver }),
    });
    const alice = cap.PeerCred{ .uid = 1000, .pid = 100 };
    const bob = cap.PeerCred{ .uid = 1001, .pid = 200 };
    try ct.bindTo(id, alice);

    const urn = Urn.from("hw:/pci/0000:01:00.0/fn0");
    // Alice — the bound peer — passes every cap check.
    try testing.expect(ct.permitsClaimFromPeer(id, &urn, .exclusive, alice));
    try testing.expect(ct.permitsRawFromPeer(id, &urn, alice));
    try testing.expect(ct.permitsDetachFromPeer(id, &urn, alice));
    // Bob — presenting the same cap id from another connection —
    // is rejected on EVERY check, regardless of the cap's authority.
    // This is the confusion-attack closure: a leaked id is useless
    // to a non-bound peer.
    try testing.expect(!ct.permitsClaimFromPeer(id, &urn, .exclusive, bob));
    try testing.expect(!ct.permitsRawFromPeer(id, &urn, bob));
    try testing.expect(!ct.permitsDetachFromPeer(id, &urn, bob));
}

test "cap binding: bindTo is idempotent for the same peer" {
    var ct = cap.CapTable.init(testing.allocator);
    defer ct.deinit();
    const id = try ct.mint(.{
        .scope = Urn.from("hw:/**"),
        .rights = RightSet.of(&.{.claim_exclusive}),
    });
    const alice = cap.PeerCred{ .uid = 1000, .pid = 100 };
    try ct.bindTo(id, alice);
    try ct.bindTo(id, alice); // second call to same peer is a no-op success
    try ct.bindTo(id, alice); // and a third — idempotent
}

test "cap binding: bindTo REFUSES to re-bind a bound cap to a different peer" {
    var ct = cap.CapTable.init(testing.allocator);
    defer ct.deinit();
    const id = try ct.mint(.{
        .scope = Urn.from("hw:/**"),
        .rights = RightSet.of(&.{.claim_exclusive}),
    });
    const alice = cap.PeerCred{ .uid = 1000, .pid = 100 };
    const bob = cap.PeerCred{ .uid = 1001, .pid = 200 };
    try ct.bindTo(id, alice);
    // A second peer attempting to steal the cap's binding fails —
    // the cap belongs to one identity for life.
    try testing.expectError(Err.NotPermitted, ct.bindTo(id, bob));
}

test "cap binding: bindTo on an unknown cap id returns NotFound" {
    var ct = cap.CapTable.init(testing.allocator);
    defer ct.deinit();
    const ghost = cap.PeerCred{ .uid = 1000, .pid = 100 };
    try testing.expectError(Err.NotFound, ct.bindTo(99999, ghost));
}


// === Defense-in-depth: peer check at the core layer ========================
// The broker accept loop already binds the cap to the first peer (server.zig).
// These tests pin the SAME binding being enforced one layer down, inside
// Core.claimWithCap / rawWithCap — so an attacker who
// somehow reached this layer with the wrong peer still fails.

test "core+peer: a BOUND cap presented from the wrong peer is refused at the core layer" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    var ct = cap.CapTable.init(testing.allocator);
    defer ct.deinit();
    const id = try ct.mint(.{
        .scope = Urn.from("hw:/**"),
        .rights = RightSet.of(&.{ .observe, .claim_exclusive, .raw }),
    });
    const alice = cap.PeerCred{ .uid = 1000, .pid = 100 };
    const bob = cap.PeerCred{ .uid = 1001, .pid = 200 };
    try ct.bindTo(id, alice);

    var core = Core.initWithCaps(testing.allocator, try seeded(&fb), &ct);
    defer core.deinit();
    const pci = Urn.from("hw:/pci/0000:01:00.0/fn0");

    // Alice — the bound peer — succeeds.
    const lease = try core.claimWithCap(id, alice, &pci, .exclusive, 1, kabi.Deadline.none);
    _ = try core.rawWithCap(id, alice, lease, 1, kabi.Deadline.none);
    try core.release(lease, 1, kabi.Deadline.none);

    // Bob — presenting the SAME cap id — is refused at the core layer.
    // The verifier's binding check fires BEFORE the lattice / hardware
    // path, so atomicity is preserved (no lease residue, no hardware touched).
    try testing.expectError(
        Err.NotPermitted,
        core.claimWithCap(id, bob, &pci, .exclusive, 2, kabi.Deadline.none),
    );
    try testing.expectEqual(@as(usize, 0), core.liveLeaseCount());
}

test "core+peer: passing null peer falls back to legacy non-bound check (back-compat)" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    var ct = cap.CapTable.init(testing.allocator);
    defer ct.deinit();
    const id = try ct.mint(.{
        .scope = Urn.from("hw:/**"),
        .rights = RightSet.of(&.{.claim_exclusive}),
    });
    // Cap is UNBOUND — both the legacy methods and the FromPeer(null) methods
    // should accept it. This pins the back-compat path for in-process callers
    // that don't have a connection identity.
    var core = Core.initWithCaps(testing.allocator, try seeded(&fb), &ct);
    defer core.deinit();
    const pci = Urn.from("hw:/pci/0000:01:00.0/fn0");

    const lease = try core.claimWithCap(id, null, &pci, .exclusive, 1, kabi.Deadline.none);
    try core.release(lease, 1, kabi.Deadline.none);
}

test "core+peer: claimDetachWithCap enforces binding on BOTH the claim and detach checks" {
    var fb = FakeBackend.init(testing.allocator);
    defer fb.deinit();
    var ct = cap.CapTable.init(testing.allocator);
    defer ct.deinit();
    const id = try ct.mint(.{
        .scope = Urn.from("hw:/**"),
        .rights = RightSet.of(&.{ .claim_exclusive, .detach_driver }),
    });
    const alice = cap.PeerCred{ .uid = 1000, .pid = 100 };
    const bob = cap.PeerCred{ .uid = 1001, .pid = 200 };
    try ct.bindTo(id, alice);

    var core = Core.initWithCaps(testing.allocator, try seeded(&fb), &ct);
    defer core.deinit();
    const pci = Urn.from("hw:/pci/0000:01:00.0/fn0");

    // Bob is rejected on the claim step (binding check fires first); the
    // detach check is never reached, but the test asserts the OUTCOME, not
    // the path. The point: both rights checks honor the binding.
    try testing.expectError(
        Err.NotPermitted,
        core.claimDetachWithCap(id, bob, &pci, .exclusive, 2, kabi.Deadline.none),
    );
    try testing.expectEqual(@as(usize, 0), core.liveLeaseCount());
}

// === Tier-0 #2 layer-1 — unforgeable cap ids (U3 closure) ==================
//
// These tests pin the U3 closure: a freshly-minted cap id MUST be unguessable
// (high-entropy, not sequential), MUST be unique within the table, MUST NOT
// be 0 (the wire sentinel), and the lookup MUST refuse 0.

test "cap U3: minted ids are NOT sequential — high-entropy by construction" {
    var ct = cap.CapTable.init(testing.allocator);
    defer ct.deinit();
    const a = try ct.mint(.{
        .scope = Urn.from("hw:/**"),
        .rights = RightSet.of(&.{.observe}),
    });
    const b = try ct.mint(.{
        .scope = Urn.from("hw:/**"),
        .rights = RightSet.of(&.{.observe}),
    });
    const c = try ct.mint(.{
        .scope = Urn.from("hw:/**"),
        .rights = RightSet.of(&.{.observe}),
    });
    // No id is 0 (the wire sentinel)
    try testing.expect(a != 0);
    try testing.expect(b != 0);
    try testing.expect(c != 0);
    // No id collides
    try testing.expect(a != b);
    try testing.expect(b != c);
    try testing.expect(a != c);
    // Not sequential: at LEAST one pair must differ by more than 1.
    // (sequential would be a=1, b=2, c=3, which only differ by 1)
    const max_seq_delta: u64 = 1;
    const delta_ab = if (a > b) a - b else b - a;
    const delta_bc = if (b > c) b - c else c - b;
    try testing.expect(delta_ab > max_seq_delta or delta_bc > max_seq_delta);
}

test "cap U3: get(0) returns null — the wire sentinel is never resolvable" {
    var ct = cap.CapTable.init(testing.allocator);
    defer ct.deinit();
    _ = try ct.mint(.{
        .scope = Urn.from("hw:/**"),
        .rights = RightSet.of(&.{.observe}),
    });
    const urn = Urn.from("hw:/pci/0000:01:00.0/fn0");
    // permitsClaim with id=0 must return false (no cap presented).
    try testing.expect(!ct.permitsClaim(0, &urn, .observe));
    try testing.expect(!ct.permitsRaw(0, &urn));
    try testing.expect(!ct.permitsDetach(0, &urn));
}

test "cap U3: minting 100 caps yields 100 distinct non-zero ids" {
    var ct = cap.CapTable.init(testing.allocator);
    defer ct.deinit();
    var ids: [100]u64 = undefined;
    for (&ids) |*id_slot| {
        id_slot.* = try ct.mint(.{
            .scope = Urn.from("hw:/**"),
            .rights = RightSet.of(&.{.observe}),
        });
        try testing.expect(id_slot.* != 0);
    }
    // Every pair must be distinct.
    for (ids, 0..) |a, i| {
        for (ids[i + 1 ..]) |b| {
            try testing.expect(a != b);
        }
    }
}

test "cap U3: attenuated ids are ALSO unforgeable (not parent_id + 1)" {
    var ct = cap.CapTable.init(testing.allocator);
    defer ct.deinit();
    const parent = try ct.mint(.{
        .scope = Urn.from("hw:/**"),
        .rights = RightSet.of(&.{ .observe, .claim_exclusive }),
    });
    const child = try ct.attenuate(parent, .{ .rights = RightSet.of(&.{.observe}) });
    try testing.expect(child != 0);
    try testing.expect(child != parent);
    // The child id must not be a trivial offset (parent+1, +2, etc.).
    const delta = if (child > parent) child - parent else parent - child;
    try testing.expect(delta > 100); // any "guess the next id" attack fails
}

// ---- R-CAP-ATTEN-WIRE: peer- and grant-gated attenuation ----------------

test "attenuateFromPeer: requires the `grant` right" {
    var ct = cap.CapTable.init(testing.allocator);
    defer ct.deinit();
    const alice = cap.PeerCred{ .uid = 1000, .pid = 100 };
    // A cap WITHOUT grant cannot delegate, even to itself.
    const no_grant = try ct.mint(.{
        .scope = Urn.from("hw:/**"),
        .rights = RightSet.of(&.{ .observe, .claim_exclusive }),
    });
    try ct.bindTo(no_grant, alice);
    try testing.expectError(
        Err.NotPermitted,
        ct.attenuateFromPeer(no_grant, alice, .{ .scope = "hw:/usb/**" }),
    );
    // A cap WITH grant can.
    const grantor = try ct.mint(.{
        .scope = Urn.from("hw:/**"),
        .rights = RightSet.of(&.{ .observe, .grant }),
    });
    try ct.bindTo(grantor, alice);
    const child = try ct.attenuateFromPeer(grantor, alice, .{ .scope = "hw:/usb/**" });
    try testing.expect(child != 0 and child != grantor);
}

test "attenuateFromPeer: enforces the connection binding" {
    var ct = cap.CapTable.init(testing.allocator);
    defer ct.deinit();
    const alice = cap.PeerCred{ .uid = 1000, .pid = 100 };
    const bob = cap.PeerCred{ .uid = 1001, .pid = 200 };
    const id = try ct.mint(.{
        .scope = Urn.from("hw:/**"),
        .rights = RightSet.of(&.{ .observe, .grant }),
    });
    try ct.bindTo(id, alice);
    // Bob holds the (leaked) id but isn't the bound peer — refused, so a
    // leaked grant-bearing id can't be used to mint sub-caps elsewhere.
    try testing.expectError(
        Err.NotPermitted,
        ct.attenuateFromPeer(id, bob, .{ .scope = "hw:/usb/**" }),
    );
    // Alice — the bound peer — succeeds.
    _ = try ct.attenuateFromPeer(id, alice, .{ .scope = "hw:/usb/**" });
}

test "attenuateFromPeer: child inherits the parent's binding + still cannot widen" {
    var ct = cap.CapTable.init(testing.allocator);
    defer ct.deinit();
    const alice = cap.PeerCred{ .uid = 1000, .pid = 100 };
    const root = try ct.mint(.{
        .scope = Urn.from("hw:/**"),
        .rights = RightSet.of(&.{ .observe, .claim_exclusive, .grant }),
    });
    try ct.bindTo(root, alice);
    const child = try ct.attenuateFromPeer(root, alice, .{ .scope = "hw:/usb/**" });
    // The child is bound to the same peer (inherited), so Alice can keep
    // delegating from it, but Bob cannot.
    const bob = cap.PeerCred{ .uid = 1001, .pid = 200 };
    _ = try ct.attenuateFromPeer(child, alice, .{ .scope = "hw:/usb/bus1/**" });
    try testing.expectError(
        Err.NotPermitted,
        ct.attenuateFromPeer(child, bob, .{ .scope = "hw:/usb/bus1/**" }),
    );
    // The narrowing invariant still holds through the peer path: a child
    // cannot widen its scope back out.
    try testing.expectError(
        Err.NotPermitted,
        ct.attenuateFromPeer(child, alice, .{ .scope = "hw:/**" }),
    );
}

test "attenuateFromPeer: missing parent is NotPermitted (no existence leak)" {
    var ct = cap.CapTable.init(testing.allocator);
    defer ct.deinit();
    const alice = cap.PeerCred{ .uid = 1000, .pid = 100 };
    try testing.expectError(
        Err.NotPermitted,
        ct.attenuateFromPeer(0xDEAD_BEEF, alice, .{ .scope = "hw:/usb/**" }),
    );
}

// ---------------------------------------------------------------------------
// CAP-01 / D-039 — capability revocation.
//
// `revoke` exists so the broker can mint a capability per CONNECTION and take
// it back on disconnect. Before it, the table had no removal at all, which is
// why the broker minted one root capability for its whole lifetime and bound
// it to the first peer that connected — making multi-operator impossible.
// ---------------------------------------------------------------------------

test "revoke: removes the capability and refuses it afterwards" {
    var ct = cap.CapTable.init(testing.allocator);
    defer ct.deinit();
    const alice = cap.PeerCred{ .uid = 1000, .pid = 100 };
    const urn = Urn.from("hw:/usb/bus1/dev4/if0");

    const id = try ct.mint(.{
        .scope = Urn.from("hw:/**"),
        .rights = RightSet.of(&.{ .observe, .claim_exclusive }),
        .bound_to = alice,
    });
    try testing.expect(ct.permitsClaimFromPeer(id, &urn, .exclusive, alice));
    try testing.expectEqual(@as(usize, 1), ct.size());

    try testing.expectEqual(@as(usize, 1), ct.revoke(id));
    try testing.expectEqual(@as(usize, 0), ct.size());
    // The authority is gone, not merely unreachable.
    try testing.expect(!ct.permitsClaimFromPeer(id, &urn, .exclusive, alice));
}

test "revoke: is idempotent on an unknown or already-revoked id" {
    var ct = cap.CapTable.init(testing.allocator);
    defer ct.deinit();
    const id = try ct.mint(.{
        .scope = Urn.from("hw:/**"),
        .rights = RightSet.of(&.{.observe}),
    });
    try testing.expectEqual(@as(usize, 1), ct.revoke(id));
    // Second revoke of the same id, and a never-minted id: both no-ops.
    // The broker's teardown defer runs unconditionally, so this must not
    // be an error path.
    try testing.expectEqual(@as(usize, 0), ct.revoke(id));
    try testing.expectEqual(@as(usize, 0), ct.revoke(0xDEAD_BEEF));
    try testing.expectEqual(@as(usize, 0), ct.revoke(0)); // wire sentinel
}

test "revoke: takes attenuated children and grandchildren with it" {
    var ct = cap.CapTable.init(testing.allocator);
    defer ct.deinit();
    const alice = cap.PeerCred{ .uid = 1000, .pid = 100 };
    const usb = Urn.from("hw:/usb/bus1/dev4/if0");

    const root = try ct.mint(.{
        .scope = Urn.from("hw:/**"),
        .rights = RightSet.of(&.{ .observe, .claim_exclusive, .grant }),
        .bound_to = alice,
    });
    // A connection delegating a narrower view to a sub-component, and that
    // sub-component delegating narrower again (R-CAP-ATTEN-WIRE).
    const child = try ct.attenuate(root, .{ .scope = "hw:/usb/**" });
    const grandchild = try ct.attenuate(child, .{ .scope = "hw:/usb/bus1/**" });
    try testing.expectEqual(@as(usize, 3), ct.size());
    try testing.expect(ct.permitsClaim(grandchild, &usb, .exclusive));

    // Revoking the root must take the whole lineage. If it did not, a
    // connection could mint a sub-cap, disconnect, and leave behind
    // authority that outlives the connection it derived from — the very
    // lifetime bug per-connection caps exist to remove, one level down.
    try testing.expectEqual(@as(usize, 3), ct.revoke(root));
    try testing.expectEqual(@as(usize, 0), ct.size());
    try testing.expect(!ct.permitsClaim(child, &usb, .exclusive));
    try testing.expect(!ct.permitsClaim(grandchild, &usb, .exclusive));
}

test "revoke: leaves unrelated capabilities untouched" {
    var ct = cap.CapTable.init(testing.allocator);
    defer ct.deinit();
    const alice = cap.PeerCred{ .uid = 1000, .pid = 100 };
    const bob = cap.PeerCred{ .uid = 1001, .pid = 200 };
    const usb = Urn.from("hw:/usb/bus1/dev4/if0");

    // Two connections, each with its own capability and its own child —
    // the multi-operator shape this whole change exists to make possible.
    const a_root = try ct.mint(.{
        .scope = Urn.from("hw:/**"),
        .rights = RightSet.of(&.{ .observe, .claim_exclusive, .grant }),
        .bound_to = alice,
    });
    const b_root = try ct.mint(.{
        .scope = Urn.from("hw:/**"),
        .rights = RightSet.of(&.{ .observe, .claim_exclusive, .grant }),
        .bound_to = bob,
    });
    const a_child = try ct.attenuate(a_root, .{ .scope = "hw:/usb/**" });
    const b_child = try ct.attenuate(b_root, .{ .scope = "hw:/usb/**" });
    try testing.expectEqual(@as(usize, 4), ct.size());

    // Alice disconnects. Exactly her lineage goes.
    try testing.expectEqual(@as(usize, 2), ct.revoke(a_root));
    try testing.expectEqual(@as(usize, 2), ct.size());
    try testing.expect(!ct.permitsClaim(a_child, &usb, .exclusive));
    // Bob is entirely unaffected — his cap still works, from his peer.
    try testing.expect(ct.permitsClaimFromPeer(b_root, &usb, .exclusive, bob));
    try testing.expect(ct.permitsClaim(b_child, &usb, .exclusive));
    // And Alice's revoked cap cannot be presented by anyone, including Bob.
    try testing.expect(!ct.permitsClaimFromPeer(a_root, &usb, .exclusive, bob));
}

test "CAP-01: two peers hold their own capabilities at the same time" {
    var ct = cap.CapTable.init(testing.allocator);
    defer ct.deinit();
    const alice = cap.PeerCred{ .uid = 1000, .pid = 100 };
    const bob = cap.PeerCred{ .uid = 1001, .pid = 200 };
    const urn = Urn.from("hw:/usb/bus1/dev4/if0");

    // THE regression pin for CAP-01. Under the old scheme there was one
    // shared capability and `bindTo` gave it to whoever arrived first;
    // the second peer was refused NotPermitted at the handshake and
    // multi-operator was impossible. Minting per connection, bound at
    // birth, is what makes both of these true at once.
    const a = try ct.mint(.{
        .scope = Urn.from("hw:/**"),
        .rights = RightSet.of(&.{ .observe, .claim_exclusive }),
        .bound_to = alice,
    });
    const b = try ct.mint(.{
        .scope = Urn.from("hw:/**"),
        .rights = RightSet.of(&.{ .observe, .claim_exclusive }),
        .bound_to = bob,
    });
    try testing.expect(a != b); // distinct ids, CSPRNG-drawn
    try testing.expect(ct.permitsClaimFromPeer(a, &urn, .exclusive, alice));
    try testing.expect(ct.permitsClaimFromPeer(b, &urn, .exclusive, bob));

    // Each is still bound: neither peer can present the other's id.
    try testing.expect(!ct.permitsClaimFromPeer(a, &urn, .exclusive, bob));
    try testing.expect(!ct.permitsClaimFromPeer(b, &urn, .exclusive, alice));
}
