Skip to content
zit Artifact [0645afa55d]
Login

Artifact [0645afa55d]

Artifact 0645afa55d528f74e6cd1c84fc49568fff8c9c55956db30d48c4390f7a142599:


const std = @import("std");
const repostate = @import("repostate.zig");
const delta = @import("delta.zig");

const Rid = repostate.Rid;
const Mtime = repostate.Mtime;
const TagType = repostate.TagType;
const MemStore = repostate.MemStore;
const RepoState = repostate.RepoState;
const parseMtime = repostate.parseMtime;

const t = std.testing;

const h_a = "a" ** 64;
const h_b = "b" ** 64;
const h_c = "c" ** 64;
const h_d = "d" ** 64;
const h_e = "e" ** 64;
const h_g = "0" ** 64;

fn countLeaves(rs: *const RepoState) usize {
    var it = rs.leaves();
    var n: usize = 0;
    while (it.next()) |_| n += 1;
    return n;
}

test "repostate §2: intern assigns one stable rid per hash" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    const s = ms.store();
    const ra = try s.intern(h_a);
    const rb = try s.intern(h_b);
    try t.expect(ra != rb);
    try t.expectEqual(ra, try s.intern(h_a));
    try t.expectEqualStrings(h_a, s.hashOf(ra));
    try t.expectEqualStrings(h_b, s.hashOf(rb));
}

test "repostate §3.2: count enumerates dense rids so a peer can classify each entry as phantom or held" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    const s = ms.store();
    try t.expectEqual(@as(usize, 0), s.count());
    _ = try s.intern(h_a); // phantom
    _ = try s.put(h_b, "held"); // content present
    _ = try s.intern(h_c); // phantom
    try t.expectEqual(@as(usize, 3), s.count());
    // Walk 1..=count and classify via content(rid): two phantoms, one held.
    var phantoms: usize = 0;
    var held: usize = 0;
    var rid: Rid = 1;
    while (rid <= s.count()) : (rid += 1) {
        if (s.content(rid) == null) phantoms += 1 else held += 1;
    }
    try t.expectEqual(@as(usize, 2), phantoms);
    try t.expectEqual(@as(usize, 1), held);
}

test "repostate §4.2: an interned but absent artifact is a phantom with no content" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    const s = ms.store();
    const rid = try s.intern(h_a);
    try t.expectEqual(@as(?[]const u8, null), s.content(rid));
    // The referenced artifact arrives: the phantom upgrades in place.
    try t.expectEqual(rid, try s.put(h_a, "payload"));
    try t.expectEqualStrings("payload", s.content(rid).?);
    // A repeat put of the same hash is a no-op.
    try t.expectEqual(rid, try s.put(h_a, "payload"));
    try t.expectEqualStrings("payload", s.content(rid).?);
}

test "repostate §5.1: tag types encode cancel=0, singleton=1, propagate=2" {
    try t.expectEqual(0, @intFromEnum(TagType.cancel));
    try t.expectEqual(1, @intFromEnum(TagType.singleton));
    try t.expectEqual(2, @intFromEnum(TagType.propagate));
}

test "repostate §3.1: a repeated parent reference collapses to one linkage row" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    const ra = try rs.crosslink(.{ .hash = h_a, .mtime = 1 });
    const rb = try rs.crosslink(.{ .hash = h_b, .mtime = 2, .parents = &.{ h_a, h_a } });
    try t.expectEqual(@as(usize, 1), rs.parentCount(rb));
    try t.expectEqual(@as(?Rid, ra), rs.primaryParentOf(rb));
    try t.expect(!rs.isLeaf(ra));
    try t.expect(rs.isLeaf(rb));
}

test "repostate §3.2: the first listed parent is the primary parent" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    const ra = try rs.crosslink(.{ .hash = h_a, .mtime = 1 });
    _ = try rs.crosslink(.{ .hash = h_b, .mtime = 2 });
    const rc = try rs.crosslink(.{ .hash = h_c, .mtime = 3, .parents = &.{ h_a, h_b } });
    try t.expectEqual(@as(usize, 2), rs.parentCount(rc));
    try t.expectEqual(@as(?Rid, ra), rs.primaryParentOf(rc));
}

test "repostate §3.3: parentsOf yields the primary and every merge parent once" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    const ra = try rs.crosslink(.{ .hash = h_a, .mtime = 1 });
    const rb = try rs.crosslink(.{ .hash = h_b, .mtime = 2 });
    // A merge child of two independent roots: primary ra, merge rb (§3.2).
    const rc = try rs.crosslink(.{ .hash = h_c, .mtime = 3, .parents = &.{ h_a, h_b, h_a } });
    // §3.1: the repeated parent collapses, so both parents are yielded once.
    var seen_a: usize = 0;
    var seen_b: usize = 0;
    var n: usize = 0;
    var it = rs.parentsOf(rc);
    while (it.next()) |p| {
        n += 1;
        if (p == ra) seen_a += 1;
        if (p == rb) seen_b += 1;
    }
    try t.expectEqual(@as(usize, 2), n);
    try t.expectEqual(@as(usize, 1), seen_a);
    try t.expectEqual(@as(usize, 1), seen_b);
    try t.expectEqual(rs.parentCount(rc), n); // §3.3: same set parentCount counts
    // A root yields nothing.
    var root_it = rs.parentsOf(ra);
    try t.expectEqual(@as(?Rid, null), root_it.next());
}

test "repostate §3.2: a sole parent is the primary parent" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    const ra = try rs.crosslink(.{ .hash = h_a, .mtime = 1 });
    const rb = try rs.crosslink(.{ .hash = h_b, .mtime = 2, .parents = &.{h_a} });
    try t.expectEqual(@as(?Rid, ra), rs.primaryParentOf(rb));
}

test "repostate §4.2: re-crosslinking a linked artifact is a linkage no-op" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    _ = try rs.crosslink(.{ .hash = h_a, .mtime = 1 });
    const rb = try rs.crosslink(.{ .hash = h_b, .mtime = 2, .parents = &.{h_a} });
    const rb_again = try rs.crosslink(.{ .hash = h_b, .mtime = 2, .parents = &.{h_a} });
    try t.expectEqual(rb, rb_again);
    try t.expectEqual(@as(usize, 1), rs.parentCount(rb));
    try t.expectEqual(@as(usize, 1), countLeaves(&rs));
    try t.expect(rs.isLeaf(rb));
}

test "repostate §4.2: an absent parent hash yields a phantom, resolved when it arrives" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    // The child arrives first; its parent hash resolves to a phantom
    // placeholder rather than a fatal error.
    const rb = try rs.crosslink(.{ .hash = h_b, .mtime = 2, .parents = &.{h_a} });
    const ra = rs.primaryParentOf(rb).?;
    try t.expectEqual(@as(?Mtime, null), rs.mtimeOf(ra));
    // A phantom is not a check-in: it never enters the leaf table.
    try t.expect(!rs.isLeaf(ra));
    try t.expect(rs.isLeaf(rb));
    try t.expectEqual(@as(usize, 1), countLeaves(&rs));
    // The referenced artifact arrives and is crosslinked: the recorded
    // linkage becomes visible in the derived views.
    try t.expectEqual(ra, try rs.crosslink(.{ .hash = h_a, .mtime = 1 }));
    try t.expectEqual(@as(?Mtime, 1), rs.mtimeOf(ra));
    try t.expect(!rs.isLeaf(ra));
    try t.expect(rs.isLeaf(rb));
    try t.expectEqual(@as(usize, 1), countLeaves(&rs));
}

test "repostate §7.2: a child reached only via a merge edge disqualifies the leaf" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    _ = try rs.crosslink(.{ .hash = h_a, .mtime = 1 });
    const rb = try rs.crosslink(.{ .hash = h_b, .mtime = 2, .parents = &.{h_a} });
    const rc = try rs.crosslink(.{ .hash = h_c, .mtime = 3, .parents = &.{h_a} });
    const rd = try rs.crosslink(.{ .hash = h_d, .mtime = 4, .parents = &.{ h_b, h_c } });
    // rc's only child rd is reached via a non-primary (merge) edge; the
    // canonical test applies no primary/merge filter.
    try t.expect(!rs.isLeaf(rb));
    try t.expect(!rs.isLeaf(rc));
    try t.expect(rs.isLeaf(rd));
    try t.expectEqual(@as(usize, 1), countLeaves(&rs));
}

test "repostate §7.3: a root check-in with no children is a leaf" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    const ra = try rs.crosslink(.{ .hash = h_a, .mtime = 1 });
    try t.expect(rs.isLeaf(ra));
    var it = rs.leaves();
    try t.expectEqual(@as(?Rid, ra), it.next());
    try t.expectEqual(@as(?Rid, null), it.next());
}

test "repostate §7.3: a new child retroactively removes its parent's leaf status" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    const ra = try rs.crosslink(.{ .hash = h_a, .mtime = 1 });
    try t.expect(rs.isLeaf(ra));
    const rb = try rs.crosslink(.{ .hash = h_b, .mtime = 2, .parents = &.{h_a} });
    try t.expect(!rs.isLeaf(ra));
    try t.expect(rs.isLeaf(rb));
}

test "repostate §7.3: full rebuild reproduces the incrementally maintained table" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    _ = try rs.crosslink(.{ .hash = h_a, .mtime = 1 });
    const rb = try rs.crosslink(.{ .hash = h_b, .mtime = 2, .parents = &.{h_a} });
    const rc = try rs.crosslink(.{ .hash = h_c, .mtime = 3, .parents = &.{h_a} });
    _ = try rs.crosslink(.{ .hash = h_d, .mtime = 4, .parents = &.{ h_b, h_c } });
    // An independent root with no children: a candidate the rebuild MUST
    // include even though it appears in no parent-link.
    const re = try rs.crosslink(.{ .hash = h_e, .mtime = 5 });
    var before: [8]Rid = undefined;
    const n_before = collectLeaves(&rs, &before);
    try rs.rebuildLeaves();
    var after: [8]Rid = undefined;
    const n_after = collectLeaves(&rs, &after);
    try t.expectEqual(n_before, n_after);
    std.mem.sort(Rid, before[0..n_before], {}, std.sort.asc(Rid));
    std.mem.sort(Rid, after[0..n_after], {}, std.sort.asc(Rid));
    try t.expectEqualSlices(Rid, before[0..n_before], after[0..n_after]);
    try t.expect(rs.isLeaf(re));
    try t.expect(!rs.isLeaf(rb));
    try t.expect(!rs.isLeaf(rc));
}

test "repostate §7.2/§6.1: a fork onto a new branch leaves the parent a leaf of its own branch" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    const ra = try rs.crosslink(.{ .hash = h_a, .mtime = 1 });
    const rb = try rs.crosslink(.{ .hash = h_b, .mtime = 2, .parents = &.{h_a}, .tags = &.{
        .{ .type = .propagate, .name = "branch", .target = null, .value = "feature" },
    } });
    try t.expect(rs.isLeaf(ra));
    try t.expect(rs.isLeaf(rb));
}

test "repostate §7.6: directly applying a branch tag re-evaluates leaf status" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    const ra = try rs.crosslink(.{ .hash = h_a, .mtime = 1 });
    _ = try rs.crosslink(.{ .hash = h_b, .mtime = 2, .parents = &.{h_a} });
    try t.expect(!rs.isLeaf(ra)); // same branch, has a child
    _ = try rs.crosslink(.{ .hash = h_c, .mtime = 3, .tags = &.{
        .{ .type = .propagate, .name = "branch", .target = h_b, .value = "feature" },
    } });
    try t.expect(rs.isLeaf(ra));
}

test "repostate §7.6: branch propagation re-evaluates a descendant's leaf status" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    const ra = try rs.crosslink(.{ .hash = h_a, .mtime = 1 });
    const rb = try rs.crosslink(.{ .hash = h_b, .mtime = 2, .parents = &.{h_a} });
    // C carries its own direct branch tag, so it blocks any further
    // propagation past it (Section 5.5: a nonzero-srcid row is never
    // overwritten by an inherited one).
    const rc = try rs.crosslink(.{ .hash = h_c, .mtime = 3, .parents = &.{h_b}, .tags = &.{
        .{ .type = .propagate, .name = "branch", .target = null, .value = "trunk" },
    } });
    try t.expect(!rs.isLeaf(ra));
    try t.expect(!rs.isLeaf(rb)); // same branch (trunk) as its child C
    try t.expect(rs.isLeaf(rc));
    // A, a pre-existing check-in with a child already in place, now gets a
    // branch tag. The walk reaches B — B carries no direct branch row of
    // its own, so it inherits "feature" — while C's direct "trunk" row
    // blocks the walk from reaching any further. B did not itself get
    // crosslinked by this call, so nothing but the propagation step re-
    // evaluates it. Derivation Section 7.6 second bullet: "when a branch
    // tag propagates to descendants, each descendant that gains or loses
    // the propagating tag MUST have its leaf status re-evaluated."
    _ = try rs.crosslink(.{ .hash = h_a, .mtime = 10, .tags = &.{
        .{ .type = .propagate, .name = "branch", .target = null, .value = "feature" },
    } });
    try t.expect(!rs.isLeaf(ra)); // A still shares a branch with child B
    try t.expect(rs.isLeaf(rb)); // B's only child C stayed on trunk: B gained leaf status
    try t.expect(rs.isLeaf(rc));
}

test "repostate §7.4: a leaf carrying an active closed marker is not an open leaf" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    const ra = try rs.crosslink(.{ .hash = h_a, .mtime = 1, .tags = &.{
        .{ .type = .singleton, .name = "closed", .target = null, .value = null },
    } });
    try t.expect(rs.isLeaf(ra));
    try t.expect(!rs.isOpenLeaf(ra));
}

test "repostate §7.4: cancelling the closed marker reopens the leaf" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    const ra = try rs.crosslink(.{ .hash = h_a, .mtime = 5, .tags = &.{
        .{ .type = .singleton, .name = "closed", .target = null, .value = null },
    } });
    try t.expect(!rs.isOpenLeaf(ra));
    _ = try rs.crosslink(.{ .hash = h_b, .mtime = 6, .tags = &.{
        .{ .type = .cancel, .name = "closed", .target = h_a, .value = null },
    } });
    try t.expect(rs.isOpenLeaf(ra));
}

test "repostate §6.1: branchOf returns the active branch-tag value" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    const ra = try rs.crosslink(.{ .hash = h_a, .mtime = 1, .tags = &.{
        .{ .type = .propagate, .name = "branch", .target = null, .value = "trunk" },
    } });
    try t.expectEqualStrings("trunk", rs.branchOf(ra, "main"));
}

test "repostate §6.1/§6.4: a check-in with no branch tag falls back to the configured main-branch" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    const ra = try rs.crosslink(.{ .hash = h_a, .mtime = 1 });
    // "main", not the literal "trunk" — proves the configured value is
    // read, not a hardcoded default (§6.1 "MUST NOT assume a fixed string").
    try t.expectEqualStrings("main", rs.branchOf(ra, "main"));
}

test "repostate §6.4: a cancelled branch tag is not active and falls back" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    const ra = try rs.crosslink(.{ .hash = h_a, .mtime = 1, .tags = &.{
        .{ .type = .cancel, .name = "branch", .target = null, .value = null },
    } });
    try t.expectEqualStrings("main", rs.branchOf(ra, "main"));
}

test "repostate §8.2: resolves to the active sym-name carrier with the greatest event.mtime" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    _ = try rs.crosslink(.{ .hash = h_a, .mtime = 1, .tags = &.{
        .{ .type = .propagate, .name = "sym-trunk", .target = null, .value = "trunk" },
    } });
    const rb = try rs.crosslink(.{ .hash = h_b, .mtime = 5, .parents = &.{h_a} });
    // B inherits the propagating sym-trunk tag; resolution keys on each
    // carrier's own event.mtime (Section 8.2), not the tag row's stored
    // mtime, so B's later commit time outranks the tag's origin A.
    try t.expectEqual(rb, try rs.resolveName("trunk"));
}

test "repostate §8.2: closed-ness does not filter resolution" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    _ = try rs.crosslink(.{ .hash = h_a, .mtime = 1, .tags = &.{
        .{ .type = .propagate, .name = "sym-trunk", .target = null, .value = "trunk" },
    } });
    const rb = try rs.crosslink(.{ .hash = h_b, .mtime = 5, .parents = &.{h_a}, .tags = &.{
        .{ .type = .singleton, .name = "closed", .target = null, .value = null },
    } });
    try t.expect(rs.isLeaf(rb));
    try t.expect(!rs.isOpenLeaf(rb));
    try t.expectEqual(rb, try rs.resolveName("trunk"));
}

test "repostate §8.2: leaf-ness does not filter resolution" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    // Singleton keeps the tag off B, isolating "a non-leaf still resolves"
    // from Section 5.4 inheritance mechanics.
    const ra = try rs.crosslink(.{ .hash = h_a, .mtime = 10, .tags = &.{
        .{ .type = .singleton, .name = "sym-trunk", .target = null, .value = "trunk" },
    } });
    _ = try rs.crosslink(.{ .hash = h_b, .mtime = 5, .parents = &.{h_a} });
    try t.expect(!rs.isLeaf(ra));
    try t.expectEqual(ra, try rs.resolveName("trunk"));
}

test "repostate §8.2: an unknown symbolic name is rejected as NotFound" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    _ = try rs.crosslink(.{ .hash = h_a, .mtime = 1 });
    try t.expectError(error.NotFound, rs.resolveName("nope"));
}

test "repostate §8.2: a name whose only sym-tag row is cancelled is NotFound" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    _ = try rs.crosslink(.{ .hash = h_a, .mtime = 1, .tags = &.{
        .{ .type = .cancel, .name = "sym-trunk", .target = null, .value = null },
    } });
    try t.expectError(error.NotFound, rs.resolveName("trunk"));
}

test "repostate §9/§2: current-trunk resolves the configured default branch name" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    const ra = try rs.crosslink(.{ .hash = h_a, .mtime = 1, .tags = &.{
        .{ .type = .propagate, .name = "sym-trunk", .target = null, .value = "trunk" },
    } });
    try t.expectEqual(ra, try rs.currentTrunk("trunk"));
    try t.expectEqual(try rs.resolveName("trunk"), try rs.currentTrunk("trunk"));
}

test "repostate §9: current-trunk of an unknown default branch is NotFound" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    _ = try rs.crosslink(.{ .hash = h_a, .mtime = 1 });
    try t.expectError(error.NotFound, rs.currentTrunk("nope"));
}

test "repostate §9: the open leaf carries an active branch tag, is a leaf, and is not closed" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    const ra = try rs.crosslink(.{ .hash = h_a, .mtime = 1, .tags = &.{
        .{ .type = .propagate, .name = "branch", .target = null, .value = "trunk" },
    } });
    try t.expectEqual(@as(?Rid, ra), rs.openLeafOf("trunk"));
}

test "repostate §9/§6.1: a tagless leaf is not the open leaf of the default branch" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    _ = try rs.crosslink(.{ .hash = h_a, .mtime = 1 });
    // Attributed to "trunk" only through the default-branch fallback: not
    // the open leaf of trunk (§6.1's fallback caveat).
    try t.expectEqual(@as(?Rid, null), rs.openLeafOf("trunk"));
}

test "repostate §9: a non-leaf on the branch is not an open leaf" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    const ra = try rs.crosslink(.{ .hash = h_a, .mtime = 1, .tags = &.{
        .{ .type = .propagate, .name = "branch", .target = null, .value = "trunk" },
    } });
    // B, a same-branch child, disqualifies A under condition (b) even
    // though A meets (a) and (c); B — the actual leaf — wins instead.
    const rb = try rs.crosslink(.{ .hash = h_b, .mtime = 2, .parents = &.{h_a} });
    try t.expect(!rs.isLeaf(ra));
    try t.expectEqual(@as(?Rid, rb), rs.openLeafOf("trunk"));
}

test "repostate §9: a closed leaf is not an open leaf" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    const ra = try rs.crosslink(.{ .hash = h_a, .mtime = 1, .tags = &.{
        .{ .type = .propagate, .name = "branch", .target = null, .value = "trunk" },
        .{ .type = .singleton, .name = "closed", .target = null, .value = null },
    } });
    try t.expect(rs.isLeaf(ra));
    try t.expectEqual(@as(?Rid, null), rs.openLeafOf("trunk"));
}

test "repostate §9: with several open leaves the greatest mtime is selected" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    _ = try rs.crosslink(.{ .hash = h_a, .mtime = 1, .tags = &.{
        .{ .type = .propagate, .name = "branch", .target = null, .value = "trunk" },
    } });
    const rb = try rs.crosslink(.{ .hash = h_b, .mtime = 2, .parents = &.{h_a} });
    const rc = try rs.crosslink(.{ .hash = h_c, .mtime = 3, .parents = &.{h_a} });
    try t.expect(rs.isLeaf(rb));
    try t.expect(rs.isLeaf(rc));
    try t.expectEqual(@as(?Rid, rc), rs.openLeafOf("trunk"));
}

test "repostate §9: a branch with no qualifying check-in has no open leaf" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    _ = try rs.crosslink(.{ .hash = h_a, .mtime = 1, .tags = &.{
        .{ .type = .propagate, .name = "branch", .target = null, .value = "trunk" },
        .{ .type = .singleton, .name = "closed", .target = null, .value = null },
    } });
    try t.expectEqual(@as(?Rid, null), rs.openLeafOf("trunk"));
}

test "repostate §10.1: fork at trunk with one closed leaf — resolution and open-leaf agree" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    _ = try rs.crosslink(.{ .hash = h_a, .mtime = 1, .tags = &.{
        .{ .type = .propagate, .name = "branch", .target = null, .value = "trunk" },
        .{ .type = .propagate, .name = "sym-trunk", .target = null, .value = "trunk" },
    } });
    const open_leaf = try rs.crosslink(.{ .hash = h_b, .mtime = 3, .parents = &.{h_a} });
    const closed_leaf = try rs.crosslink(.{ .hash = h_c, .mtime = 2, .parents = &.{h_a}, .tags = &.{
        .{ .type = .singleton, .name = "closed", .target = null, .value = null },
    } });
    _ = try rs.crosslink(.{ .hash = h_d, .mtime = 4, .parents = &.{h_a}, .tags = &.{
        .{ .type = .cancel, .name = "sym-trunk", .target = null, .value = null },
        .{ .type = .propagate, .name = "branch", .target = null, .value = "feature" },
        .{ .type = .propagate, .name = "sym-feature", .target = null, .value = "feature" },
    } });
    try t.expect(rs.isLeaf(open_leaf));
    try t.expect(rs.isOpenLeaf(open_leaf));
    try t.expect(rs.isLeaf(closed_leaf));
    try t.expect(!rs.isOpenLeaf(closed_leaf));
    // §10.1: leaves lists the open trunk leaf while omitting the closed
    // sibling; whatis trunk agrees with that same open leaf here.
    try t.expectEqual(open_leaf, try rs.resolveName("trunk"));
    try t.expectEqual(@as(?Rid, open_leaf), rs.openLeafOf("trunk"));
}

test "repostate §10.2: a closed leaf newer than the open leaf — resolution and open-leaf diverge" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    _ = try rs.crosslink(.{ .hash = h_a, .mtime = 1, .tags = &.{
        .{ .type = .propagate, .name = "branch", .target = null, .value = "trunk" },
        .{ .type = .propagate, .name = "sym-trunk", .target = null, .value = "trunk" },
    } });
    const open_leaf = try rs.crosslink(.{ .hash = h_b, .mtime = 2, .parents = &.{h_a} });
    const closed_leaf = try rs.crosslink(.{ .hash = h_c, .mtime = 3, .parents = &.{h_a}, .tags = &.{
        .{ .type = .singleton, .name = "closed", .target = null, .value = null },
    } });
    try t.expect(rs.isOpenLeaf(open_leaf));
    try t.expect(rs.isLeaf(closed_leaf));
    try t.expect(!rs.isOpenLeaf(closed_leaf));
    // §10.2: whatis trunk reports the closed, newer check-in even though
    // the default open-leaf view omits it — resolution and open-leaf
    // enumeration diverge on this graph.
    try t.expectEqual(closed_leaf, try rs.resolveName("trunk"));
    try t.expectEqual(@as(?Rid, open_leaf), rs.openLeafOf("trunk"));
    try t.expect((try rs.resolveName("trunk")) != rs.openLeafOf("trunk").?);
}

fn collectLeaves(rs: *const RepoState, out: []Rid) usize {
    var it = rs.leaves();
    var n: usize = 0;
    while (it.next()) |rid| : (n += 1) out[n] = rid;
    return n;
}

fn crosslinkNoLeak(gpa: std.mem.Allocator) !void {
    var ms = MemStore.init(gpa);
    defer ms.deinit();
    var rs = RepoState.init(gpa, ms.store());
    defer rs.deinit();
    // Self-branch root plus a tag on a not-yet-stored (phantom) target, so
    // internTag/applyDirect/propagate all allocate.
    _ = try rs.crosslink(.{ .hash = h_a, .mtime = 1, .tags = &.{
        .{ .type = .propagate, .name = "branch", .target = null, .value = "feature" },
        .{ .type = .propagate, .name = "t1", .target = h_g, .value = "v" },
    } });
    _ = try rs.crosslink(.{ .hash = h_b, .mtime = 2, .parents = &.{h_a} });
    // Phantom parent plus a merge, so every allocation site is exercised.
    _ = try rs.crosslink(.{ .hash = h_d, .mtime = 4, .parents = &.{ h_b, h_c } });
    // A cancel and a singleton (+closed), exercising the value-clear and
    // downgrade-at-repropagation paths.
    _ = try rs.crosslink(.{ .hash = h_c, .mtime = 3, .parents = &.{h_a}, .tags = &.{
        .{ .type = .cancel, .name = "t1", .target = null, .value = null },
        .{ .type = .singleton, .name = "closed", .target = null, .value = null },
    } });
    _ = try rs.crosslink(.{ .hash = h_g, .mtime = 5 }); // the phantom target arrives
    try rs.rebuildLeaves();
}

test "repostate §4.2: crosslink survives allocation failure without leaking" {
    try t.checkAllAllocationFailures(t.allocator, crosslinkNoLeak, .{});
}

/// Fork topology reused across the root:/start:/merge-in:/branch-type
/// tests: A (self-tagged trunk) <- B (plain, inherits trunk) <- C
/// (self-tagged feature, diverging from trunk at B) <- D (plain, inherits
/// feature).
const TopoT = struct { a: Rid, b: Rid, c: Rid, d: Rid };

fn buildTopoT(rs: *RepoState) !TopoT {
    const a = try rs.crosslink(.{ .hash = h_a, .mtime = 1, .tags = &.{
        .{ .type = .propagate, .name = "sym-trunk", .target = null, .value = "trunk" },
        .{ .type = .propagate, .name = "branch", .target = null, .value = "trunk" },
    } });
    const b = try rs.crosslink(.{ .hash = h_b, .mtime = 2, .parents = &.{h_a} });
    const c = try rs.crosslink(.{ .hash = h_c, .mtime = 3, .parents = &.{h_b}, .tags = &.{
        .{ .type = .propagate, .name = "sym-feature", .target = null, .value = "feature" },
        .{ .type = .propagate, .name = "branch", .target = null, .value = "feature" },
    } });
    const d = try rs.crosslink(.{ .hash = h_d, .mtime = 4, .parents = &.{h_c} });
    return .{ .a = a, .b = b, .c = c, .d = d };
}

test "repostate §8.3: rid: resolves a numeric RID to a known check-in" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    const topo = try buildTopoT(&rs);
    var buf: [32]u8 = undefined;
    const name = try std.fmt.bufPrint(&buf, "rid:{d}", .{topo.b});
    try t.expectEqual(topo.b, try rs.resolve(name, .checkin));
}

test "repostate §8.3: rid: an unknown or non-numeric RID is NotFound" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    _ = try rs.crosslink(.{ .hash = h_a, .mtime = 1 });
    const cases = [_][]const u8{ "rid:999", "rid:xyz" };
    for (cases) |name| {
        try t.expectError(error.NotFound, rs.resolve(name, .checkin));
    }
}

test "repostate §8.3: tag: forces literal tag resolution over hash interpretation" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    const h_hash_match = "dead" ++ "2" ** 60;
    const rx = try rs.crosslink(.{ .hash = h_hash_match, .mtime = 1 });
    const ry = try rs.crosslink(.{ .hash = h_c, .mtime = 2, .tags = &.{
        .{ .type = .propagate, .name = "sym-dead", .target = null, .value = "dead" },
    } });
    try t.expectEqual(rx, try rs.resolve("dead", .checkin));
    try t.expectEqual(ry, try rs.resolve("tag:dead", .checkin));
    try t.expect((try rs.resolve("dead", .checkin)) != (try rs.resolve("tag:dead", .checkin)));
}

test "repostate §8.3: tip resolves the global maximum event.mtime check-in" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    const topo = try buildTopoT(&rs);
    try t.expectEqual(topo.d, try rs.resolve("tip", .checkin));
}

test "repostate §8.3/§8.4: root: rewrites to the first ancestor off the branch" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    const topo = try buildTopoT(&rs);
    // Walk D -> C[feature] -> B[trunk]: B is the first ancestor off feature.
    try t.expectEqual(topo.b, try rs.resolve("root:feature", .checkin));
}

test "repostate §8.3/§8.4: start: rewrites to the earliest check-in on the branch" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    const topo = try buildTopoT(&rs);
    try t.expectEqual(topo.c, try rs.resolve("start:feature", .checkin));
}

test "repostate §8.3: merge-in: rewrites to the youngest parent-branch ancestor" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    const topo = try buildTopoT(&rs);
    // Section 8.4's two-variant walk gives merge-in: the same node as
    // root: here: the youngest ancestor on the parent branch is exactly
    // the first ancestor found off the diverging branch.
    try t.expectEqual(topo.b, try rs.resolve("merge-in:feature", .checkin));
}

test "repostate §8.3: branch-type request post-processes to the branch root" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    const topo = try buildTopoT(&rs);
    try t.expectEqual(topo.c, try rs.resolve("feature", .branch));
}

test "repostate §8.3: an ambiguous hash prefix is rejected" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    const h1 = "abcd" ++ "1" ** 60;
    const h2 = "abcd" ++ "2" ** 60;
    _ = try rs.crosslink(.{ .hash = h1, .mtime = 1 });
    _ = try rs.crosslink(.{ .hash = h2, .mtime = 2 });
    try t.expectError(error.Ambiguous, rs.resolve("abcd", .checkin));
}

test "repostate §8.3: a unique hash prefix resolves to its single check-in" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    const ra = try rs.crosslink(.{ .hash = h_a, .mtime = 1 });
    try t.expectEqual(ra, try rs.resolve("aaaa", .checkin));
}

test "repostate §8.3: a trailing punctuation character is stripped and retried" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    _ = try rs.crosslink(.{ .hash = h_a, .mtime = 1, .tags = &.{
        .{ .type = .propagate, .name = "sym-trunk", .target = null, .value = "trunk" },
    } });
    try t.expectEqual(try rs.resolve("trunk", .checkin), try rs.resolve("trunk.", .checkin));
}

test "repostate §8.3: a name with no matching form is NotFound" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    _ = try rs.crosslink(.{ .hash = h_a, .mtime = 1 });
    // "zzz": no form matches and no punctuation to strip.
    try t.expectError(error.NotFound, rs.resolve("zzz", .checkin));
    // "..": the punct-retry exhausts down to an empty slice.
    try t.expectError(error.NotFound, rs.resolve("..", .checkin));
}

test "repostate §8.3: plain name falls through to the §8.2 Rule" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    _ = try rs.crosslink(.{ .hash = h_a, .mtime = 1, .tags = &.{
        .{ .type = .propagate, .name = "sym-trunk", .target = null, .value = "trunk" },
    } });
    try t.expectEqual(try rs.resolveName("trunk"), try rs.resolve("trunk", .checkin));
}

test "repostate §8.4: branch-walk is bounded by the primary-parent chain" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    const ra = try rs.crosslink(.{ .hash = h_a, .mtime = 1, .tags = &.{
        .{ .type = .propagate, .name = "sym-trunk", .target = null, .value = "trunk" },
        .{ .type = .propagate, .name = "branch", .target = null, .value = "trunk" },
    } });
    // A root-only branch: root:trunk never finds an ancestor off-branch, so
    // the walk falls back to the branch root itself.
    try t.expectEqual(ra, try rs.resolve("root:trunk", .checkin));
}

test "repostate §6.3: enumerates one entry per distinct active branch value" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    _ = try buildTopoT(&rs);
    const entries = try rs.branches(t.allocator);
    defer t.allocator.free(entries);
    try t.expectEqual(@as(usize, 2), entries.len);
    try t.expectEqualStrings("feature", entries[0].name);
    try t.expectEqualStrings("trunk", entries[1].name);
}

test "repostate §6.3: a branch entry's representative is its greatest-mtime member" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    const topo = try buildTopoT(&rs);
    const entries = try rs.branches(t.allocator);
    defer t.allocator.free(entries);
    var trunk: ?RepoState.BranchEntry = null;
    for (entries) |e| {
        if (std.mem.eql(u8, e.name, "trunk")) trunk = e;
    }
    try t.expectEqual(topo.b, trunk.?.tip);
    try t.expectEqual(@as(usize, 2), trunk.?.count);
    try t.expectEqual(@as(Mtime, 2), trunk.?.mtime);
}

test "repostate §6.3: listing-closed reflects the representative row, diverging from §9 open-leaf" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    _ = try rs.crosslink(.{ .hash = h_a, .mtime = 1, .tags = &.{
        .{ .type = .propagate, .name = "branch", .target = null, .value = "trunk" },
    } });
    const older_leaf = try rs.crosslink(.{ .hash = h_b, .mtime = 2, .parents = &.{h_a} });
    const newer_leaf = try rs.crosslink(.{ .hash = h_c, .mtime = 3, .parents = &.{h_a} });
    _ = try rs.crosslink(.{ .hash = h_d, .mtime = 5, .tags = &.{
        .{ .type = .singleton, .name = "closed", .target = h_c, .value = null },
    } });
    const entries = try rs.branches(t.allocator);
    defer t.allocator.free(entries);
    try t.expectEqual(@as(usize, 1), entries.len);
    try t.expectEqual(newer_leaf, entries[0].tip);
    try t.expect(entries[0].closed);
    try t.expectEqual(@as(?Rid, older_leaf), rs.openLeafOf("trunk"));
}

test "repostate §6.3: branches survives allocation failure without leaking" {
    try t.checkAllAllocationFailures(t.allocator, branchesNoLeak, .{});
}

fn branchesNoLeak(gpa: std.mem.Allocator) !void {
    var ms = MemStore.init(gpa);
    defer ms.deinit();
    var rs = RepoState.init(gpa, ms.store());
    defer rs.deinit();
    _ = try buildTopoT(&rs);
    const entries = try rs.branches(gpa);
    gpa.free(entries);
}

test "repostate §7.5: a non-leaf is never an ambiguous leaf" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    _ = try rs.crosslink(.{ .hash = h_a, .mtime = 1 });
    const rb = try rs.crosslink(.{ .hash = h_b, .mtime = 2, .parents = &.{h_a} });
    _ = try rs.crosslink(.{ .hash = h_c, .mtime = 3, .parents = &.{h_b} });
    try t.expect(!rs.isAmbiguousLeaf(rb));
}

test "repostate §7.5: a lone open leaf is not ambiguous" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    const ra = try rs.crosslink(.{ .hash = h_a, .mtime = 1 });
    try t.expect(!rs.isAmbiguousLeaf(ra));
}

test "repostate §7.5: two open leaves on a branch are each ambiguous" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    _ = try rs.crosslink(.{ .hash = h_a, .mtime = 1 });
    const rb1 = try rs.crosslink(.{ .hash = h_b, .mtime = 2, .parents = &.{h_a} });
    const rb2 = try rs.crosslink(.{ .hash = h_c, .mtime = 3, .parents = &.{h_a} });
    try t.expect(rs.isAmbiguousLeaf(rb1));
    try t.expect(rs.isAmbiguousLeaf(rb2));
}

test "repostate §7.5: a closed sibling does not make a leaf ambiguous" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    _ = try rs.crosslink(.{ .hash = h_a, .mtime = 1 });
    const rb1 = try rs.crosslink(.{ .hash = h_b, .mtime = 2, .parents = &.{h_a} });
    _ = try rs.crosslink(.{ .hash = h_c, .mtime = 3, .parents = &.{h_a}, .tags = &.{
        .{ .type = .singleton, .name = "closed", .target = null, .value = null },
    } });
    try t.expect(!rs.isAmbiguousLeaf(rb1));
}

test "repostate §7.5: open-leaf listing is mtime-descending" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    _ = try rs.crosslink(.{ .hash = h_a, .mtime = 1, .tags = &.{
        .{ .type = .propagate, .name = "branch", .target = null, .value = "trunk" },
    } });
    const rb1 = try rs.crosslink(.{ .hash = h_b, .mtime = 2, .parents = &.{h_a} });
    const rb2 = try rs.crosslink(.{ .hash = h_c, .mtime = 3, .parents = &.{h_a} });
    const leaves_out = try rs.openLeavesOf(t.allocator, "trunk");
    defer t.allocator.free(leaves_out);
    try t.expectEqualSlices(Rid, &.{ rb2, rb1 }, leaves_out);
}

test "repostate §7.5: openLeavesOf survives allocation failure without leaking" {
    try t.checkAllAllocationFailures(t.allocator, openLeavesOfNoLeak, .{});
}

fn openLeavesOfNoLeak(gpa: std.mem.Allocator) !void {
    var ms = MemStore.init(gpa);
    defer ms.deinit();
    var rs = RepoState.init(gpa, ms.store());
    defer rs.deinit();
    _ = try rs.crosslink(.{ .hash = h_a, .mtime = 1, .tags = &.{
        .{ .type = .propagate, .name = "branch", .target = null, .value = "trunk" },
    } });
    _ = try rs.crosslink(.{ .hash = h_b, .mtime = 2, .parents = &.{h_a} });
    _ = try rs.crosslink(.{ .hash = h_c, .mtime = 3, .parents = &.{h_a} });
    const leaves_out = try rs.openLeavesOf(gpa, "trunk");
    gpa.free(leaves_out);
}

test "repostate §8.3 fuzz: dispatch never crashes on adversarial name bytes" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    _ = try buildTopoT(&rs);
    var prng = std.Random.DefaultPrng.init(0xF055_D47E);
    const random = prng.random();
    // Every internal parser this loop can reach (rid:, hash-prefix,
    // expandTimestamp, punct-retry) sees adversarial bytes, NUL included
    // per the wire-data contract; `resolve`'s own postcondition assert
    // doubles as the invariant check — any bad candidate rid traps under
    // Debug/ReleaseSafe rather than the assertion being separately
    // reasserted here.
    const alphabet = "abcdef0123456789-: .ABCXYZ_/\\\x00";
    var buf: [40]u8 = undefined;
    var i: usize = 0;
    const iterations = 2000;
    while (i < iterations) : (i += 1) {
        const len = random.uintLessThan(usize, buf.len) + 1;
        for (buf[0..len]) |*c| c.* = alphabet[random.uintLessThan(usize, alphabet.len)];
        _ = rs.resolve(buf[0..len], .checkin) catch |err| switch (err) {
            error.NotFound, error.Ambiguous => {},
        };
    }
}

test "repostate §4.2: control named target changes branch without a carrier event or leaf" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    const parent = try rs.crosslink(.{ .hash = h_a, .mtime = 1 });
    const manifest = try rs.crosslink(.{ .hash = h_c, .mtime = 2, .parents = &.{h_a} });
    const control = try rs.ingestControlTags(h_b, 3, &.{
        .{ .type = .singleton, .name = "branch", .target = h_c, .value = "release" },
    });
    try t.expectEqualStrings("release", rs.branchOf(manifest, "trunk"));
    try t.expect(rs.isLeaf(parent));
    try t.expectEqual(manifest, rs.openLeafOf("release").?);
    try t.expect(rs.mtimeOf(control) == null);
    try t.expectEqual(@as(usize, 0), rs.parentCount(control));
    try t.expect(!rs.isLeaf(control));
    try t.expect(!rs.isOpenLeaf(control));
}

test "repostate §8.3: parseMtime accepts direct and canonical D-card datetimes" {
    const direct = parseMtime("2026-07-10 08:30:15.007").?;
    try t.expectEqual(direct, parseMtime("2026-07-10T08:30:15.007").?);
    try t.expectEqual(@as(Mtime, 0), parseMtime("1970-01-01").?);
    try t.expect(parseMtime("1970-01-01T00:00") == null);
    try t.expect(parseMtime("1969-12-31T23:59:59.999") == null);
}

test "repostate §5.1: tagsOf reports singleton/propagate/cancel per T-card sign" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    // §5.1: the leading sign selects the type — `+`→singleton, `*`→propagate,
    // `-`→cancel. A cancel row is inactive (tagtype 0) and is not surfaced.
    const ra = try rs.crosslink(.{ .hash = h_a, .mtime = 1, .tags = &.{
        .{ .type = .singleton, .name = "alpha", .target = null, .value = "av" },
        .{ .type = .cancel, .name = "beta", .target = null, .value = null },
        .{ .type = .propagate, .name = "gamma", .target = null, .value = "gv" },
    } });
    const tags = try rs.tagsOf(t.allocator, ra);
    defer t.allocator.free(tags);
    try t.expectEqual(@as(usize, 2), tags.len);
    try t.expectEqualStrings("alpha", tags[0].name);
    try t.expectEqual(TagType.singleton, tags[0].tagtype);
    try t.expectEqualStrings("av", tags[0].value.?);
    try t.expectEqualStrings("gamma", tags[1].name);
    try t.expectEqual(TagType.propagate, tags[1].tagtype);
    try t.expectEqualStrings("gv", tags[1].value.?);
}

test "repostate §5.1/§2: a later-mtime cancel drops the tag from tagsOf and tagNames" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    const ra = try rs.crosslink(.{ .hash = h_a, .mtime = 1, .tags = &.{
        .{ .type = .propagate, .name = "sym-rel", .target = null, .value = "rel" },
    } });
    // §5.1: only an active (tagtype > 0) tag is in effect. A later-mtime
    // cancel (tagtype 0) supersedes the active row and takes it out of use.
    _ = try rs.ingestControlTags(h_b, 2, &.{
        .{ .type = .cancel, .name = "sym-rel", .target = h_a, .value = null },
    });
    const tags = try rs.tagsOf(t.allocator, ra);
    defer t.allocator.free(tags);
    try t.expectEqual(@as(usize, 0), tags.len);
    const names = try rs.tagNames(t.allocator);
    defer t.allocator.free(names);
    try t.expectEqual(@as(usize, 0), names.len);
}

test "repostate §5.2: a later write supersedes; tagsOf shows one row with the newer value" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    const ra = try rs.crosslink(.{ .hash = h_a, .mtime = 1, .tags = &.{
        .{ .type = .propagate, .name = "sym-x", .target = null, .value = "old" },
    } });
    // §5.2 UNIQUE (rid, tag): a later write for the same (rid, tag) supersedes
    // the earlier one — one live entry, carrying the newer value.
    _ = try rs.ingestControlTags(h_b, 2, &.{
        .{ .type = .propagate, .name = "sym-x", .target = h_a, .value = "new" },
    });
    const tags = try rs.tagsOf(t.allocator, ra);
    defer t.allocator.free(tags);
    try t.expectEqual(@as(usize, 1), tags.len);
    try t.expectEqualStrings("sym-x", tags[0].name);
    try t.expectEqualStrings("new", tags[0].value.?);
}

test "repostate §5.2: tagsOf surfaces each active row's stored value payload" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    const ra = try rs.crosslink(.{ .hash = h_a, .mtime = 1, .tags = &.{
        .{ .type = .singleton, .name = "note", .target = null, .value = "hello world" },
    } });
    const tags = try rs.tagsOf(t.allocator, ra);
    defer t.allocator.free(tags);
    try t.expectEqual(@as(usize, 1), tags.len);
    try t.expectEqualStrings("note", tags[0].name);
    try t.expectEqualStrings("hello world", tags[0].value.?);
}

test "repostate §4.2: a tag on an absent UUID is invisible until that artifact arrives" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    _ = try rs.crosslink(.{ .hash = h_a, .mtime = 1 }); // plain root, no tags
    // §4.2 step 1: a tag targeting an absent artifact interns a phantom
    // placeholder. Its only holder is a phantom, so the name is not yet in use.
    _ = try rs.ingestControlTags(h_c, 2, &.{
        .{ .type = .propagate, .name = "sym-rel", .target = h_b, .value = "rel" },
    });
    {
        const names = try rs.tagNames(t.allocator);
        defer t.allocator.free(names);
        try t.expectEqual(@as(usize, 0), names.len);
    }
    // The referenced artifact arrives and is crosslinked: the tag on it
    // becomes visible (§4.2 step 1).
    _ = try rs.crosslink(.{ .hash = h_b, .mtime = 3 });
    {
        const names = try rs.tagNames(t.allocator);
        defer t.allocator.free(names);
        try t.expectEqual(@as(usize, 1), names.len);
        try t.expectEqualStrings("sym-rel", names[0]);
    }
}

test "repostate §4.2/§5.4: a * tag surfaces on the primary child, a + tag does not" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    const ra = try rs.crosslink(.{ .hash = h_a, .mtime = 1, .tags = &.{
        .{ .type = .propagate, .name = "sym-star", .target = null, .value = "sv" },
        .{ .type = .singleton, .name = "sym-solo", .target = null, .value = "so" },
    } });
    const rb = try rs.crosslink(.{ .hash = h_b, .mtime = 2, .parents = &.{h_a} });
    // §5.4: the propagating (*) tag reaches the primary child; the singleton
    // (+) tag affects only its target and triggers no walk.
    const child = try rs.tagsOf(t.allocator, rb);
    defer t.allocator.free(child);
    try t.expectEqual(@as(usize, 1), child.len);
    try t.expectEqualStrings("sym-star", child[0].name);
    // The origin carries both its own singleton and propagating tags.
    const origin = try rs.tagsOf(t.allocator, ra);
    defer t.allocator.free(origin);
    try t.expectEqual(@as(usize, 2), origin.len);
    try t.expectEqualStrings("sym-solo", origin[0].name);
    try t.expectEqualStrings("sym-star", origin[1].name);
}

test "repostate §6.4: tagsOf surfaces the active tagid-8 branch tag with its value" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    const ra = try rs.crosslink(.{ .hash = h_a, .mtime = 1, .tags = &.{
        .{ .type = .propagate, .name = "branch", .target = null, .value = "trunk" },
    } });
    // §6.4: branch membership is the active tagid-8 tag. tagsOf surfaces it
    // with its stored value (the branch name).
    const tags = try rs.tagsOf(t.allocator, ra);
    defer t.allocator.free(tags);
    try t.expectEqual(@as(usize, 1), tags.len);
    try t.expectEqualStrings("branch", tags[0].name);
    try t.expectEqual(TagType.propagate, tags[0].tagtype);
    try t.expectEqualStrings("trunk", tags[0].value.?);
}

test "repostate §2: tagNames returns raw reserved-prefix names; only sym- is user-facing" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    // §2 reserves the 'sym-'/'wiki-'/'tkt-'/'event-' prefixes and the fixed
    // 'branch'/'closed' names. tagNames returns them raw — presentation (the
    // 'sym-' stripping that makes a name user-facing) is the caller's job.
    _ = try rs.crosslink(.{ .hash = h_a, .mtime = 1, .tags = &.{
        .{ .type = .propagate, .name = "branch", .target = null, .value = "trunk" },
        .{ .type = .propagate, .name = "sym-trunk", .target = null, .value = null },
        .{ .type = .singleton, .name = "wiki-Home", .target = null, .value = null },
    } });
    const names = try rs.tagNames(t.allocator);
    defer t.allocator.free(names);
    try t.expectEqual(@as(usize, 3), names.len);
    try t.expectEqualStrings("branch", names[0]);
    try t.expectEqualStrings("sym-trunk", names[1]);
    try t.expectEqualStrings("wiki-Home", names[2]);
}

test "repostate §4.2: a crosslinked artifact carries no implicit cluster tag (content-type unmodeled)" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    // §4.2 step 3 applies an implicit singleton cluster tag to cluster
    // artifacts. The crosslink layer does not yet carry artifact content-type
    // on a Record, so no cluster tag is ever created; this codifies that a
    // plain crosslinked artifact surfaces none.
    const ra = try rs.crosslink(.{ .hash = h_a, .mtime = 1 });
    const tags = try rs.tagsOf(t.allocator, ra);
    defer t.allocator.free(tags);
    try t.expectEqual(@as(usize, 0), tags.len);
    const names = try rs.tagNames(t.allocator);
    defer t.allocator.free(names);
    try t.expectEqual(@as(usize, 0), names.len);
}

test "repostate §5.2: tagsOf and tagNames survive allocation failure without leaking" {
    try t.checkAllAllocationFailures(t.allocator, tagsNoLeak, .{});
}

fn tagsNoLeak(gpa: std.mem.Allocator) !void {
    var ms = MemStore.init(gpa);
    defer ms.deinit();
    var rs = RepoState.init(gpa, ms.store());
    defer rs.deinit();
    const ra = try rs.crosslink(.{ .hash = h_a, .mtime = 1, .tags = &.{
        .{ .type = .propagate, .name = "branch", .target = null, .value = "trunk" },
        .{ .type = .propagate, .name = "sym-trunk", .target = null, .value = null },
    } });
    const tags = try rs.tagsOf(gpa, ra);
    gpa.free(tags);
    const names = try rs.tagNames(gpa);
    gpa.free(names);
}

// ---------------------------------------------------------------------------
// Verbatim wire storage (sync §4.1/§7.2): a MemStore entry may hold the stored
// §4.1 container it retransmits, materialising its plaintext lazily.
// ---------------------------------------------------------------------------

const flate = std.compress.flate;

/// A §4.1 container (4-byte big-endian uncompressed length + RFC1950 zlib) —
/// the test's own encoder, mirroring the storage layer's, so a test never
/// depends on a production encode entry point.
fn makeContainer(gpa: std.mem.Allocator, bytes: []const u8) ![]u8 {
    var aw = std.Io.Writer.Allocating.init(gpa);
    defer aw.deinit();
    try aw.ensureUnusedCapacity(64);
    try aw.writer.writeInt(u32, @intCast(bytes.len), .big);
    const window = try gpa.alloc(u8, flate.max_window_len);
    defer gpa.free(window);
    var c = try flate.Compress.init(&aw.writer, window, .zlib, .level_6);
    try c.writer.writeAll(bytes);
    try c.finish();
    return try aw.toOwnedSlice();
}

test "repostate sync §4.1/§7.2: putWire stores the container; wire() serves it, content() inflates lazily and memoises" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();

    const content = "the stored container's plaintext, materialised on first read\n";
    const container = try makeContainer(t.allocator, content);
    defer t.allocator.free(container);
    const rid = try ms.putWire(h_a, container);

    // wire() returns the stored container verbatim (borrowed).
    const wf = ms.store().wire(rid).?;
    try t.expectEqualSlices(u8, container, wf.container);

    // content() inflates the container to the original bytes, and memoises: a
    // second read returns the very same slice (the borrowed-slice contract).
    const first = ms.store().content(rid).?;
    try t.expectEqualStrings(content, first);
    const second = ms.store().content(rid).?;
    try t.expectEqual(first.ptr, second.ptr); // memoised, not re-inflated
}

test "repostate sync §7.2: wire() is null for a raw put and for a phantom" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    const raw_rid = try ms.store().put(h_a, "raw bytes"); // no stored container
    try t.expect(ms.store().wire(raw_rid) == null);
    const ph_rid = try ms.store().intern(h_b); // phantom
    try t.expect(ms.store().wire(ph_rid) == null);
    try t.expect(ms.store().content(ph_rid) == null);
}

test "repostate sync §4.1: putWire is idempotent and keeps the first stored container" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    const content = "idempotent putWire keeps the first container";
    const c1 = try makeContainer(t.allocator, content);
    defer t.allocator.free(c1);
    const c2 = try makeContainer(t.allocator, content);
    defer t.allocator.free(c2);
    const rid1 = try ms.putWire(h_a, c1);
    const rid2 = try ms.putWire(h_a, c2); // same hash: no-op
    try t.expectEqual(rid1, rid2);
    try t.expectEqualStrings(content, ms.store().content(rid1).?);
}

test "repostate sync §7.2: putWireDelta serves the delta form; content() reconstructs against the basis and memoises" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();

    const base = "the basis artifact whose long shared run lets the delta be a small copy-dominated payload distinct from the reconstructed size";
    const target = "the basis artifact whose long shared run lets the delta be a small copy-dominated payload distinct from the reconstructed size!!";
    // The basis is stored first (an earlier rid) as a full container.
    const base_container = try makeContainer(t.allocator, base);
    defer t.allocator.free(base_container);
    _ = try ms.putWire(h_a, base_container);

    // The delta form: a §4.1 container of the raw FossilDelta against h_a.
    const raw = try delta.create(t.allocator, base, target);
    defer t.allocator.free(raw);
    const delta_container = try makeContainer(t.allocator, raw);
    defer t.allocator.free(delta_container);
    const target_size = try delta.targetSize(raw);
    const rid = try ms.putWireDelta(h_b, delta_container, h_a, target_size);

    // wire() returns the delta arm: the stored container plus DELTASRC and the
    // reconstructed-target size (the §7.2 USIZE — NOT the container prefix).
    const wf = ms.store().wire(rid).?;
    try t.expect(wf.delta != null);
    try t.expectEqualSlices(u8, delta_container, wf.container);
    try t.expectEqualStrings(h_a, wf.delta.?.src_hash);
    try t.expectEqual(@as(u64, target.len), wf.delta.?.target_size);

    // content() reconstructs the plaintext against the (materialised) basis and
    // memoises: a second read returns the same slice.
    const first = ms.store().content(rid).?;
    try t.expectEqualStrings(target, first);
    const second = ms.store().content(rid).?;
    try t.expectEqual(first.ptr, second.ptr);

    // A delta whose basis is absent yields null content (not a crash), never a
    // wrong reconstruction.
    const raw2 = try delta.create(t.allocator, base, target);
    defer t.allocator.free(raw2);
    const dc2 = try makeContainer(t.allocator, raw2);
    defer t.allocator.free(dc2);
    const orphan = try ms.putWireDelta(h_c, dc2, h_d, target.len); // h_d never stored
    try t.expect(ms.store().content(orphan) == null);
}

fn putWireOom(gpa: std.mem.Allocator, container: []const u8) !void {
    var ms = MemStore.init(gpa);
    defer ms.deinit();
    _ = try ms.putWire(h_a, container);
}

fn putWireDeltaOom(gpa: std.mem.Allocator, base_container: []const u8, delta_container: []const u8) !void {
    var ms = MemStore.init(gpa);
    defer ms.deinit();
    _ = try ms.putWire(h_a, base_container);
    _ = try ms.putWireDelta(h_b, delta_container, h_a, 128);
}

test "repostate sync §7.2: putWireDelta propagates allocation failure" {
    const base_container = try makeContainer(t.allocator, "basis for the putWireDelta allocation-failure probe, with a shared run");
    defer t.allocator.free(base_container);
    const raw = try delta.create(t.allocator, "basis for the putWireDelta allocation-failure probe, with a shared run", "basis for the putWireDelta allocation-failure probe, with a shared run!");
    defer t.allocator.free(raw);
    const delta_container = try makeContainer(t.allocator, raw);
    defer t.allocator.free(delta_container);
    try t.checkAllAllocationFailures(t.allocator, putWireDeltaOom, .{ base_container, delta_container });
}

test "repostate sync §7.2/§4.1: retain records the received full container on an already-put entry; wire() then serves it verbatim" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    const s = ms.store();

    // The receive path stores reconstructed plaintext FIRST (put), so the entry
    // already carries bytes — the case putWire would decline.
    const content = "the received artifact plaintext, stored via put before the wire is retained\n";
    const rid = try s.put(h_a, content);
    try t.expect(s.wire(rid) == null); // no wire yet

    // retain() records the received §4.1 container even though bytes is set.
    const container = try makeContainer(t.allocator, content);
    defer t.allocator.free(container);
    try s.retain(rid, .{ .full = container });

    const wf = s.wire(rid).?;
    try t.expect(wf.delta == null);
    try t.expectEqualSlices(u8, container, wf.container); // §7.2 verbatim
    // content() still returns the original plaintext (the put'd bytes stand).
    try t.expectEqualStrings(content, s.content(rid).?);
}

test "repostate sync §7.2: retain records the received delta wire form; wire() serves the delta arm with DELTASRC + USIZE" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    const s = ms.store();

    const target = "the reconstructed target the receiver stored, distinct in size from the raw delta payload\n";
    const rid = try s.put(h_b, target); // plaintext stored by the receive path

    const base = "the reconstructed target the receiver stored, distinct in size from the raw delta payload!!";
    const raw = try delta.create(t.allocator, base, target);
    defer t.allocator.free(raw);
    const delta_container = try makeContainer(t.allocator, raw);
    defer t.allocator.free(delta_container);
    const target_size = try delta.targetSize(raw);
    try s.retain(rid, .{ .delta = .{ .src = h_a, .container = delta_container, .target_size = target_size } });

    const wf = s.wire(rid).?;
    try t.expect(wf.delta != null);
    try t.expectEqualSlices(u8, delta_container, wf.container);
    try t.expectEqualStrings(h_a, wf.delta.?.src_hash);
    try t.expectEqual(@as(u64, target.len), wf.delta.?.target_size);
    // content() is unchanged — the plaintext the receiver already reconstructed.
    try t.expectEqualStrings(target, s.content(rid).?);
}

test "repostate sync §4.1: retain is idempotent — the first retained form wins" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    const s = ms.store();
    const content = "idempotent retain keeps the first container";
    const rid = try s.put(h_a, content);
    const c1 = try makeContainer(t.allocator, content);
    defer t.allocator.free(c1);
    const c2 = try makeContainer(t.allocator, content);
    defer t.allocator.free(c2);
    try s.retain(rid, .{ .full = c1 });
    try s.retain(rid, .{ .full = c2 }); // no-op: first form stands
    try t.expectEqualSlices(u8, c1, s.wire(rid).?.container);
}

fn retainFullOom(gpa: std.mem.Allocator, container: []const u8) !void {
    var ms = MemStore.init(gpa);
    defer ms.deinit();
    const s = ms.store();
    const rid = try s.put(h_a, "retain OOM probe plaintext");
    try s.retain(rid, .{ .full = container });
}

test "repostate sync §7.2: retain (full) propagates allocation failure" {
    const container = try makeContainer(t.allocator, "retain full allocation-failure probe container payload");
    defer t.allocator.free(container);
    try t.checkAllAllocationFailures(t.allocator, retainFullOom, .{container});
}

fn retainDeltaOom(gpa: std.mem.Allocator, delta_container: []const u8) !void {
    var ms = MemStore.init(gpa);
    defer ms.deinit();
    const s = ms.store();
    const rid = try s.put(h_b, "retain delta OOM probe plaintext");
    try s.retain(rid, .{ .delta = .{ .src = h_a, .container = delta_container, .target_size = 128 } });
}

test "repostate sync §7.2: retain (delta) propagates allocation failure" {
    const raw = try delta.create(t.allocator, "retain delta allocation-failure probe basis with a shared run here", "retain delta allocation-failure probe basis with a shared run here!");
    defer t.allocator.free(raw);
    const delta_container = try makeContainer(t.allocator, raw);
    defer t.allocator.free(delta_container);
    try t.checkAllAllocationFailures(t.allocator, retainDeltaOom, .{delta_container});
}

test "repostate sync §4.1: putWire propagates allocation failure" {
    const container = try makeContainer(t.allocator, "payload for the putWire allocation-failure probe");
    defer t.allocator.free(container);
    try t.checkAllAllocationFailures(t.allocator, putWireOom, .{container});
}

// --- bisectSpan (ambiguities.md bisect-midpoint) -------------------------------

// Extra distinct hashes for larger DAG fixtures; digit prefixes order below the
// letter hashes ("0" < "1" < ... < "a"), so hash tiebreaks are controllable.
const h_1 = "1" ** 64;
const h_2 = "2" ** 64;
const h_3 = "3" ** 64;

test "repostate bisect-midpoint: even span probes the lower median by mtime" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    // A six-node chain c0<-c1<-c2<-c3<-c4<-c5 with strictly increasing mtime.
    const c0 = try rs.crosslink(.{ .hash = h_g, .mtime = 10 });
    const c1 = try rs.crosslink(.{ .hash = h_1, .mtime = 20, .parents = &.{h_g} });
    const c2 = try rs.crosslink(.{ .hash = h_2, .mtime = 30, .parents = &.{h_1} });
    _ = try rs.crosslink(.{ .hash = h_3, .mtime = 40, .parents = &.{h_2} });
    _ = try rs.crosslink(.{ .hash = h_a, .mtime = 50, .parents = &.{h_3} });
    const c5 = try rs.crosslink(.{ .hash = h_b, .mtime = 60, .parents = &.{h_a} });
    // good=c0, bad=c5 → untested {c1,c2,c3,c4} (even); probe = index (4-1)/2 = 1
    // by ascending mtime = c2 (the earlier of the two middle elements).
    const out = try rs.bisectSpan(t.allocator, &.{c5}, &.{c0}, &.{});
    try t.expectEqual(@as(usize, 4), out.untested);
    try t.expectEqual(@as(?Rid, c2), out.probe);
    try t.expectEqual(c5, out.culprit);
    _ = c1;
}

test "repostate bisect-midpoint: mtime tie broken by least artifact hash" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    // c1 and c2 share mtime 50; c1 carries the higher hash ("b"), c2 the lower
    // ("a"), so the lower-median of {c1,c2} is c2 by the hash tiebreak.
    const c0 = try rs.crosslink(.{ .hash = h_g, .mtime = 10 });
    const c1 = try rs.crosslink(.{ .hash = h_b, .mtime = 50, .parents = &.{h_g} });
    const c2 = try rs.crosslink(.{ .hash = h_a, .mtime = 50, .parents = &.{h_b} });
    const c3 = try rs.crosslink(.{ .hash = h_c, .mtime = 90, .parents = &.{h_a} });
    const out = try rs.bisectSpan(t.allocator, &.{c3}, &.{c0}, &.{});
    try t.expectEqual(@as(usize, 2), out.untested);
    try t.expectEqual(@as(?Rid, c2), out.probe);
    _ = c1;
}

test "repostate bisect-midpoint: full-ancestry candidates span every merge path" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    // Diamond: root r, left L (primary), right R (merge parent), merge M.
    _ = try rs.crosslink(.{ .hash = h_g, .mtime = 10 });
    const left = try rs.crosslink(.{ .hash = h_a, .mtime = 20, .parents = &.{h_g} });
    const right = try rs.crosslink(.{ .hash = h_b, .mtime = 30, .parents = &.{h_g} });
    const m = try rs.crosslink(.{ .hash = h_c, .mtime = 40, .parents = &.{ h_a, h_b } });
    // Marking R good leaves L reachable; marking L good leaves R reachable only
    // via the non-primary merge edge — proving full-ancestry membership, never a
    // primary-only mainline walk.
    const via_left = try rs.bisectSpan(t.allocator, &.{m}, &.{right}, &.{});
    try t.expectEqual(@as(?Rid, left), via_left.probe);
    const via_right = try rs.bisectSpan(t.allocator, &.{m}, &.{left}, &.{});
    try t.expectEqual(@as(?Rid, right), via_right.probe);
}

test "repostate bisect-midpoint: narrowing terminates at the mtime-earliest bad" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    const c0 = try rs.crosslink(.{ .hash = h_g, .mtime = 10 });
    const c1 = try rs.crosslink(.{ .hash = h_1, .mtime = 20, .parents = &.{h_g} });
    const c2 = try rs.crosslink(.{ .hash = h_2, .mtime = 30, .parents = &.{h_1} });
    const c3 = try rs.crosslink(.{ .hash = h_3, .mtime = 40, .parents = &.{h_2} });
    const c4 = try rs.crosslink(.{ .hash = h_a, .mtime = 50, .parents = &.{h_3} });
    // Step 1: good=c0, bad=c4 → untested {c1,c2,c3}, probe = median c2.
    const s1 = try rs.bisectSpan(t.allocator, &.{c4}, &.{c0}, &.{});
    try t.expectEqual(@as(?Rid, c2), s1.probe);
    // Step 2: c2 marked bad → anchor becomes c2, untested {c1}, probe c1.
    const s2 = try rs.bisectSpan(t.allocator, &.{ c4, c2 }, &.{c0}, &.{});
    try t.expectEqual(@as(?Rid, c1), s2.probe);
    try t.expectEqual(c2, s2.culprit);
    // Step 3: c1 marked good → no untested candidate; culprit = c2 (final).
    const s3 = try rs.bisectSpan(t.allocator, &.{ c4, c2 }, &.{ c0, c1 }, &.{});
    try t.expectEqual(@as(?Rid, null), s3.probe);
    try t.expectEqual(@as(usize, 0), s3.untested);
    try t.expectEqual(c2, s3.culprit);
    _ = c3;
}

test "repostate bisect-midpoint: skipped candidates drop from the untested set" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    const c0 = try rs.crosslink(.{ .hash = h_g, .mtime = 10 });
    const c1 = try rs.crosslink(.{ .hash = h_1, .mtime = 20, .parents = &.{h_g} });
    const c2 = try rs.crosslink(.{ .hash = h_2, .mtime = 30, .parents = &.{h_1} });
    const c3 = try rs.crosslink(.{ .hash = h_3, .mtime = 40, .parents = &.{h_2} });
    // good=c0, bad=c3, skip c2 → untested {c1} only.
    const out = try rs.bisectSpan(t.allocator, &.{c3}, &.{c0}, &.{c2});
    try t.expectEqual(@as(usize, 1), out.untested);
    try t.expectEqual(@as(?Rid, c1), out.probe);
}

test "repostate bisect-midpoint: an inverted mark set is refused" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    const c0 = try rs.crosslink(.{ .hash = h_g, .mtime = 10 });
    _ = try rs.crosslink(.{ .hash = h_1, .mtime = 20, .parents = &.{h_g} });
    const c2 = try rs.crosslink(.{ .hash = h_2, .mtime = 30, .parents = &.{h_1} });
    // bad=c0 is an ancestor of good=c2 → inverted.
    try t.expectError(error.InvertedMarks, rs.bisectSpan(t.allocator, &.{c0}, &.{c2}, &.{}));
}

test "repostate bisect-midpoint: unrelated histories are refused" {
    var ms = MemStore.init(t.allocator);
    defer ms.deinit();
    var rs = RepoState.init(t.allocator, ms.store());
    defer rs.deinit();
    // Two independent roots share no ancestor.
    const x = try rs.crosslink(.{ .hash = h_a, .mtime = 10 });
    const y = try rs.crosslink(.{ .hash = h_b, .mtime = 20 });
    try t.expectError(error.UnrelatedHistories, rs.bisectSpan(t.allocator, &.{x}, &.{y}, &.{}));
}