Skip to content
zit Artifact [2f5a65a28a]
Login

Artifact [2f5a65a28a]

Artifact 2f5a65a28aad0c2c8d053d941ba872f53e99414135309c82bf0a0b0efdf9e7b5:


//! Seeded, parameterized fuzz targets for the framed, content-addressed log
//! (storage-track-plan.md §C/§E) over a deterministic in-memory backend. Each
//! target takes its seed and round count from the caller (`zig build fuzz --
//! <target> [--seed N] [--rounds N]`); a fixed-seed smoke `test` per target
//! (below) delegates to the same pub fn so the same invariant also runs under
//! `zig build test`. Registered in fuzz_tests.zig.
//!
//! The disk is a zero-fault sim/FaultyFile (the healthy-disk default config, so
//! nothing tears or flips), which makes the round-trip invariants deterministic
//! and filesystem-free. delta is reached through the public `zit` module: a
//! relative import would pull delta.zig into this compilation root a second
//! time, colliding with the copy logstore.zig already holds.

const std = @import("std");
const logstore = @import("zit").logstore;
const faulty = @import("sim/faulty_file.zig");
const delta = @import("zit").delta;
const container = @import("zit").container;
const pack = @import("zit").pack;
const artifact = @import("zit").artifact;

/// A fresh in-memory backend with the healthy-disk default config — the
/// precondition every round-trip below depends on.
fn healthyFile(gpa: std.mem.Allocator, rand: std.Random) faulty.FaultyFile {
    const file = faulty.FaultyFile.init(gpa, rand);
    std.debug.assert(std.meta.eql(file.cfg, faulty.FaultCfg{}));
    return file;
}

/// A random `min_hash_len..max_hash_len` byte hash into `buf`. Hashes are
/// opaque here (never verified against content), so arbitrary bytes are fine.
fn randomHash(rand: std.Random, buf: *[logstore.max_hash_len]u8) []const u8 {
    const span = logstore.max_hash_len - logstore.min_hash_len + 1;
    const len = logstore.min_hash_len + rand.uintLessThan(usize, span);
    for (buf[0..len]) |*b| b.* = rand.int(u8);
    return buf[0..len];
}

/// `open` never crashes on garbage appended after a valid header: it recovers a
/// store or fails with one of its declared errors (storage-track-plan.md §C
/// torn-tail recovery).
///
/// Reachability, asserted rather than assumed (the `serve_fuzz` idea): a run
/// must reach BOTH a recovered store (the torn tail truncated away) and a
/// `Corrupt` rejection, or the generator has drifted so torn-tail recovery is
/// never exercised. Measured at seed 1, 5_000 rounds: 197 recovered / 4_803
/// Corrupt (≈4% recover), and at 256 rounds recovery holds ≥8 across seeds 1-3
/// and the smoke seed, the floor. `OutOfMemory` and `Storage` are excluded on
/// measured grounds: this target runs over a healthy file with a real
/// allocator, so neither is reachable here (0/5_000) — they are pinned by the
/// allocator-failure and `FaultyFile` storage sweeps.
const open_garbage_min_rounds: usize = 256;
pub fn openGarbage(gpa: std.mem.Allocator, seed: u64, rounds: usize) !void {
    var prng = std.Random.DefaultPrng.init(seed);
    const rand = prng.random();
    var recovered: usize = 0;
    var corrupt: usize = 0;
    var round: usize = 0;
    while (round < rounds) : (round += 1) {
        var backend = healthyFile(gpa, rand);
        defer backend.deinit();
        const file = backend.storageFile();

        var seeded = try logstore.LogStore.open(gpa, file, 0);
        seeded.deinit(gpa);

        var garbage: [256]u8 = undefined;
        const n = rand.uintLessThan(usize, garbage.len + 1);
        rand.bytes(garbage[0..n]);
        try file.append(garbage[0..n]);

        if (logstore.LogStore.open(gpa, file, 0)) |store| {
            var opened = store;
            opened.deinit(gpa);
            recovered += 1;
        } else |err| switch (err) {
            error.OutOfMemory, error.Storage => {},
            error.Corrupt => corrupt += 1,
        }
    }
    if (rounds >= open_garbage_min_rounds and (recovered == 0 or corrupt == 0)) {
        std.debug.print(
            "logstore_open_garbage: {d} rounds reached recovered={d} corrupt={d} — " ++
                "the appended-garbage generator no longer straddles recovery and rejection\n",
            .{ rounds, recovered, corrupt },
        );
        return error.OutcomeUnreached;
    }
}

/// §C/sync §4.1 — putZlib then content round-trips the uncompressed bytes: the
/// zlib container the store writes inflates back to exactly what went in.
///
/// No reachability assertion: every round is a well-formed put/get round-trip,
/// so success is the only outcome — no reject arm to partition.
pub fn zlibRoundTrip(gpa: std.mem.Allocator, seed: u64, rounds: usize) !void {
    var prng = std.Random.DefaultPrng.init(seed);
    const rand = prng.random();
    const max_raw: usize = 128;
    var hash_buf: [logstore.max_hash_len]u8 = undefined;
    var raw_buf: [max_raw]u8 = undefined;
    var round: usize = 0;
    while (round < rounds) : (round += 1) {
        var backend = healthyFile(gpa, rand);
        defer backend.deinit();
        var store = try logstore.LogStore.open(gpa, backend.storageFile(), 0);
        defer store.deinit(gpa);

        const hash = randomHash(rand, &hash_buf);
        const rlen = rand.uintLessThan(usize, max_raw + 1);
        for (raw_buf[0..rlen]) |*b| b.* = rand.int(u8);
        const raw = raw_buf[0..rlen];

        const rid = try store.putZlib(hash, raw);
        const got = (try store.content(gpa, rid)).?;
        defer gpa.free(got);
        try std.testing.expectEqualSlices(u8, raw, got);
    }
}

/// §C/delta §4 — putDelta then content applies the delta and round-trips the
/// target: a delta frame reconstructs its target by walking to the base frame
/// and applying via delta.apply.
///
/// No reachability assertion: every round is a well-formed put/get round-trip,
/// so success is the only outcome — no reject arm to partition.
pub fn deltaRoundTrip(gpa: std.mem.Allocator, seed: u64, rounds: usize) !void {
    var prng = std.Random.DefaultPrng.init(seed);
    const rand = prng.random();
    const max_len: usize = 128;
    var base_buf: [max_len]u8 = undefined;
    var target_buf: [max_len]u8 = undefined;
    var base_hash: [20]u8 = undefined;
    var target_hash: [20]u8 = undefined;
    var round: usize = 0;
    while (round < rounds) : (round += 1) {
        var backend = healthyFile(gpa, rand);
        defer backend.deinit();
        var store = try logstore.LogStore.open(gpa, backend.storageFile(), 0);
        defer store.deinit(gpa);

        const blen = 1 + rand.uintLessThan(usize, max_len);
        for (base_buf[0..blen]) |*b| b.* = rand.int(u8);
        const base = base_buf[0..blen];
        const tlen = 1 + rand.uintLessThan(usize, max_len);
        for (target_buf[0..tlen]) |*b| b.* = rand.int(u8);
        const target = target_buf[0..tlen];

        // Distinct hashes: put keys on the hash, so a base/target collision
        // would alias the two frames and defeat the round-trip.
        for (&base_hash) |*b| b.* = rand.int(u8);
        for (&target_hash) |*b| b.* = rand.int(u8);
        base_hash[0] = 0;
        target_hash[0] = 1;

        const d = try delta.create(gpa, base, target);
        defer gpa.free(d);
        const base_rid = try store.put(&base_hash, base);
        const target_rid = try store.putDelta(&target_hash, base_rid, d);
        const got = (try store.content(gpa, target_rid)).?;
        defer gpa.free(got);
        try std.testing.expectEqualSlices(u8, target, got);
    }
}

/// §5 — pickBase/putArtifact over random content and random candidate sets
/// preserves the invariant "storage is a cache of the log": whatever base
/// policy chooses, `content` returns the exact bytes that went in. And any
/// delta pickBase accepts both reconstructs its target and clears the 75%
/// accept bar, against an eligible (non-phantom, under-cap) base.
///
/// No reachability assertion: every round is a well-formed put/get round-trip
/// with fixed accept invariants, so success is the only outcome — no reject arm
/// to partition.
pub fn pickBaseRoundTrip(gpa: std.mem.Allocator, seed: u64, rounds: usize) !void {
    var prng = std.Random.DefaultPrng.init(seed);
    const rand = prng.random();
    const max_len: usize = 160;
    var buf: [max_len]u8 = undefined;
    var hash_buf: [logstore.max_hash_len]u8 = undefined;
    var thash_buf: [logstore.max_hash_len]u8 = undefined;
    var round: usize = 0;
    while (round < rounds) : (round += 1) {
        var backend = healthyFile(gpa, rand);
        defer backend.deinit();
        var store = try logstore.LogStore.open(gpa, backend.storageFile(), 0);
        defer store.deinit(gpa);

        // Seed a handful of content frames — some sharing a long prefix so
        // profitable deltas exist, some pure noise — each put through the full
        // best-of-N write path with a random (possibly ineligible) base hint.
        // Every stored frame must round-trip regardless of the chosen encoding.
        const seed_frames = 1 + rand.uintLessThan(usize, 8);
        var rids: [8]logstore.Rid = undefined;
        var nr: usize = 0;
        while (nr < seed_frames) : (nr += 1) {
            const len = 1 + rand.uintLessThan(usize, max_len);
            for (buf[0..len]) |*b| b.* = rand.int(u8);
            if (nr > 0 and rand.boolean()) @memset(buf[0..@min(len, 48)], 0x5A);
            const hash = randomHash(rand, &hash_buf);
            // Content addressing: distinct content ⇒ distinct hash. `randomHash`
            // can emit a 1-byte hash that collides across seed frames, which
            // would (correctly) hit `putArtifact`'s idempotent short-circuit and
            // alias two different contents to one rid — a harness artifact, not a
            // store bug (real hashes never collide). Stamp the frame index into
            // byte 0 (`seed_frames <= 8`, and `hash.len >= 1`) so every seed
            // frame is a distinct key, mirroring the deltaRoundTrip guard above.
            hash_buf[0] = @intCast(nr);
            const hint: ?logstore.Rid =
                if (nr > 0 and rand.boolean()) rids[rand.uintLessThan(usize, nr)] else null;
            const rid = try store.putArtifact(hash, buf[0..len], hint);
            const got = (try store.content(gpa, rid)).?;
            defer gpa.free(got);
            try std.testing.expectEqualSlices(u8, buf[0..len], got);
            rids[nr] = rid;
        }

        // Now probe pickBase directly with a random candidate multiset (may
        // over-offer past max_base_candidates, repeat rids, or be empty).
        var cands: [12]logstore.Rid = undefined;
        const cn = rand.uintLessThan(usize, @min(nr, cands.len) + 1);
        for (cands[0..cn]) |*c| c.* = rids[rand.uintLessThan(usize, nr)];

        const tlen = 1 + rand.uintLessThan(usize, max_len);
        for (buf[0..tlen]) |*b| b.* = rand.int(u8);
        if (rand.boolean()) @memset(buf[0..@min(tlen, 48)], 0x5A);
        const target = buf[0..tlen];
        const thash = randomHash(rand, &thash_buf);

        if (try store.pickBase(gpa, thash, target, cands[0..cn])) |pick| {
            defer gpa.free(pick.delta);
            // Accepted ⇒ strictly under 75% of the uncompressed artifact.
            try std.testing.expect(@as(u64, pick.delta.len) * 4 < @as(u64, target.len) * 3);
            // Chosen base is eligible: content-bearing and under the write cap.
            try std.testing.expect(!store.isPhantom(pick.base));
            try std.testing.expect(store.depthOf(pick.base) < logstore.delta_chain_write_max);
            // …and the delta reconstructs the target byte-for-byte.
            const base_bytes = (try store.content(gpa, pick.base)).?;
            defer gpa.free(base_bytes);
            const rebuilt = try delta.apply(gpa, base_bytes, pick.delta);
            defer gpa.free(rebuilt);
            try std.testing.expectEqualSlices(u8, target, rebuilt);
        }
    }
}

/// §6.1/§7.3 — pack-redeltify round-trip: a fuzzed store mixing every frame
/// class pack must handle (raw / zlib / local delta / verbatim wire delta /
/// interned phantom / config) is repacked through the REAL `zit.pack.packLog`,
/// and EVERY artifact must decode-all byte-identically before and after the
/// pack. Because `packLog` re-hashes each reconstructed frame against its name
/// (§7.7), every content frame is keyed by `sha3-256(content)` — the digest a
/// 64-hex name verifies against — so the fuzzer models real content addressing,
/// not opaque keys. The packed base graph is chosen by our policy, so this pins
/// that a whole-store re-basing never perturbs a single reconstructed byte.
///
/// No reachability assertion: every round builds a store and repacks it, a
/// decode-all round-trip whose only outcome is success — no reject arm to
/// partition.
pub fn packRoundTrip(gpa: std.mem.Allocator, seed: u64, rounds: usize) !void {
    var prng = std.Random.DefaultPrng.init(seed);
    const rand = prng.random();
    const max_frames: usize = 20;
    const max_len: usize = 200;
    var round: usize = 0;
    while (round < rounds) : (round += 1) {
        var backend = healthyFile(gpa, rand);
        defer backend.deinit();
        var src = try logstore.LogStore.open(gpa, backend.storageFile(), 0);
        defer src.deinit(gpa);

        // A live config sometimes (pack must carry exactly one through).
        if (rand.boolean()) {
            try src.putConfig(.{ .hash_policy = 2, .default_branch = "trunk", .project_id = "pid" });
        }

        // Model every content frame written, in append order: its sha3 key, its
        // owned uncompressed bytes, and the src rid it landed at (a delta base
        // for later frames). Phantoms carry no content and are not modeled here.
        var keys: [max_frames][32]u8 = undefined;
        var contents: [max_frames][]u8 = undefined;
        var rids: [max_frames]logstore.Rid = undefined;
        var nf: usize = 0;
        defer for (contents[0..nf]) |c| gpa.free(c);

        const nframes = 1 + rand.uintLessThan(usize, max_frames);
        var i: usize = 0;
        while (i < nframes) : (i += 1) {
            const len = 1 + rand.uintLessThan(usize, max_len);
            const bytes = try gpa.alloc(u8, len);
            var freed = false;
            errdefer if (!freed) gpa.free(bytes);
            for (bytes) |*b| b.* = rand.int(u8);
            // Bias toward a shared run with an earlier frame so real (profitable)
            // deltas occur, not only literal-only ones.
            if (nf > 0 and rand.boolean()) {
                const src_frame = contents[rand.uintLessThan(usize, nf)];
                const run = @min(len, src_frame.len);
                @memcpy(bytes[0..run], src_frame[0..run]);
            }
            var key: [32]u8 = undefined;
            std.crypto.hash.sha3.Sha3_256.hash(bytes, &key, .{});
            // Content addressing: identical content ⇒ identical key ⇒ the store's
            // idempotent short-circuit would alias two model entries to one rid.
            // Skip a duplicate rather than model a phantom second frame.
            if (src.lookup(&key) != null) {
                gpa.free(bytes);
                freed = true;
                continue;
            }
            // Choose an on-disk form. Deltas need an existing content base.
            const variant: u8 = if (nf == 0) rand.uintLessThan(u8, 2) else rand.uintLessThan(u8, 4);
            const rid = switch (variant) {
                0 => try src.put(&key, bytes), // raw
                1 => try src.putZlib(&key, bytes), // zlib full form
                2 => try src.putArtifact(&key, bytes, rids[rand.uintLessThan(usize, nf)]), // local delta (may fall back to full)
                3 => blk: { // verbatim wire delta over an existing base
                    const bi = rand.uintLessThan(usize, nf);
                    const raw = delta.create(gpa, contents[bi], bytes) catch |e| switch (e) {
                        error.OutOfMemory => return error.OutOfMemory,
                        error.TargetTooLarge => unreachable, // len <= 200
                    };
                    defer gpa.free(raw);
                    const cont = container.encode(gpa, raw, .default) catch |e| switch (e) {
                        error.OutOfMemory => return error.OutOfMemory,
                        error.InputTooLarge => unreachable, // a <=200-byte delta always encodes
                    };
                    defer gpa.free(cont);
                    break :blk try src.putDeltaContainer(&key, rids[bi], cont);
                },
                else => unreachable,
            };
            keys[nf] = key;
            contents[nf] = bytes;
            rids[nf] = rid;
            nf += 1;
        }

        // An interned phantom (no frame on disk) that pack must tolerate and not
        // resurrect. Keyed off a distinct label so it never collides with content.
        var phantom: [32]u8 = undefined;
        var label: [16]u8 = undefined;
        rand.bytes(&label);
        std.crypto.hash.sha3.Sha3_256.hash(&label, &phantom, .{});
        const had_phantom = src.lookup(&phantom) == null;
        if (had_phantom) _ = try src.intern(&phantom);

        try src.commit();

        // Pack through the REAL transform into a fresh healthy store.
        var pbackend = healthyFile(gpa, rand);
        defer pbackend.deinit();
        var packed_store = try logstore.LogStore.open(gpa, pbackend.storageFile(), 0);
        defer packed_store.deinit(gpa);
        const stats = pack.packLog(gpa, &src, &packed_store, pack.Filter.keep_all, &.{}) catch |e| switch (e) {
            error.OutOfMemory => return error.OutOfMemory,
            error.Storage => return error.OutOfMemory, // a healthy sim never faults; treat as fatal
            error.Corrupt => return error.TestUnexpectedResult, // a §7.7 round-trip failure IS the bug
        };
        try std.testing.expectEqual(nf, stats.artifacts);

        // Decode-all identical pre/post: every modeled artifact reconstructs to
        // its exact input bytes from BOTH the source and the repacked store. And
        // §6.1 per-frame monotonicity: NO packed frame is larger on disk than its
        // source frame — the guard keeps the smaller of {existing, re-encoding}.
        // Holds absolutely here because `max_frames` (20) keeps every chain below
        // the read cap, so `copySrcFrame`'s §3.3 deep-chain fallback (the one path
        // that can enlarge a KEPT frame) is never taken.
        for (keys[0..nf], contents[0..nf]) |k, want| {
            const srid = src.lookup(&k).?;
            const sb = (try src.content(gpa, srid)).?;
            defer gpa.free(sb);
            const prid = packed_store.lookup(&k) orelse return error.TestUnexpectedResult;
            const pb = (try packed_store.content(gpa, prid)).?;
            defer gpa.free(pb);
            try std.testing.expectEqualSlices(u8, want, sb);
            try std.testing.expectEqualSlices(u8, want, pb);
            try std.testing.expect(packed_store.frameSpanOf(prid) <= src.frameSpanOf(srid));
        }
        // The phantom carries no content, so pack never writes a frame for it.
        if (had_phantom) try std.testing.expect(packed_store.lookup(&phantom) == null);
        // §6.1 whole-store monotonicity: the repack never regressed — per-frame
        // non-worsening plus dropped superseded configs make this exact.
        try std.testing.expect(stats.bytes_after <= stats.bytes_before);
    }
}

/// A one-file check-in manifest (`file_name` → `blob_name64`, optional primary
/// parent `parent_name`, a root check-in carrying a propagating `branch=trunk`
/// T card) — a valid parseable manifest so pack's §6.2 walk (`deriveCandidateHints`
/// → `artifact.parseForImport`) recognizes it as a check-in and records the
/// F-card blob under its path. Returns owned bytes; only OOM escapes.
fn spCheckin(
    gpa: std.mem.Allocator,
    ts: []const u8,
    parent_name: ?[]const u8,
    file_name: []const u8,
    blob_name64: []const u8,
) error{OutOfMemory}![]u8 {
    var pbuf: [1]artifact.PCard = undefined;
    var p_slice: []const artifact.PCard = &.{};
    if (parent_name) |pn| {
        pbuf[0] = .{ .parents = pn, .count = 1 };
        p_slice = pbuf[0..1];
    }
    const fcards = [_]artifact.FCard{
        .{ .filename = file_name, .hash = blob_name64, .perm = null, .old_name = null, .mode = .regular },
    };
    const root_tags = [_]artifact.TCard{
        .{ .sign = .propagate, .name = "branch", .target = null, .value = "trunk" },
    };
    var m: artifact.Manifest = .{
        .arena_state = std.heap.ArenaAllocator.init(gpa),
        .kind = .manifest,
        .a = null,
        .b = null,
        .c = .{ .comment = "c" },
        .d = .{ .timestamp = ts },
        .e = null,
        .g = null,
        .h = null,
        .i = null,
        .k = null,
        .l = null,
        .n = null,
        .r = null,
        .u = .{ .login = "u" },
        .z = null,
        .w = null,
        .f = &fcards,
        .j = &.{},
        .m = &.{},
        .p = p_slice,
        .q = &.{},
        .t = if (parent_name == null) &root_tags else &.{},
    };
    defer m.deinit();
    return artifact.create(&m, gpa);
}

/// The most tracked files / versions / poor bases one same-path round-trip
/// builds — every loop and stack array below is sized to these.
const sp_min_files: usize = 4;
const sp_max_files: usize = 6;
const sp_min_versions: usize = 2;
const sp_max_versions: usize = 4;
const sp_noise_blobs: usize = 2;
/// files × versions blobs + the same count of manifests + noise blobs — the
/// upper bound on modeled content frames one round produces.
const sp_max_frames: usize = sp_max_files * sp_max_versions * 2 + sp_noise_blobs;

/// §6.2/§7.3 — same-path pack round-trip: a fuzzed repository of several tracked
/// files, each evolving over interleaved single-file check-ins (so a file's
/// earlier version sits OUTSIDE the bounded chronological window of its later
/// version — reachable only through pack's §6.2 same-path manifest walk), with
/// blobs in a per-seed mix of full / local-delta / verbatim-wire-delta-over-a-
/// poor-base encodings, is repacked through the REAL `zit.pack.packLog`. Every
/// artifact (blobs AND manifests, incl. the trunk tip) must decode byte-identically
/// before and after the pack, and no packed frame may exceed its source frame
/// (§6.1 monotonic). Because `packLog` re-hashes each reconstructed frame against
/// its name (§7.7), every frame is keyed by `sha3-256(content)` — the digest a
/// 64-hex name verifies against — so the same-path walk resolves real F-card
/// names, not opaque keys.
///
/// No reachability assertion: every round builds a store and repacks it, a
/// decode-all round-trip whose only outcome is success — no reject arm to
/// partition.
pub fn packSamePathRoundTrip(gpa: std.mem.Allocator, seed: u64, rounds: usize) !void {
    var prng = std.Random.DefaultPrng.init(seed);
    const rand = prng.random();
    var round: usize = 0;
    while (round < rounds) : (round += 1) {
        var backend = healthyFile(gpa, rand);
        defer backend.deinit();
        var src = try logstore.LogStore.open(gpa, backend.storageFile(), 0);
        defer src.deinit(gpa);

        try src.putConfig(.{ .hash_policy = 2, .default_branch = "trunk", .project_id = "pid" });

        // Every modeled content frame in append order: its sha3 key + owned
        // uncompressed bytes (the ground truth every store must decode to).
        var keys: [sp_max_frames][32]u8 = undefined;
        var contents: [sp_max_frames][]u8 = undefined;
        var nf: usize = 0;
        defer for (contents[0..nf]) |c| gpa.free(c);

        // Poor bases first (lowest offset): full-form noise blobs a source wire
        // delta names and pack must discard for the same-path predecessor.
        var noise_rid: [sp_noise_blobs]logstore.Rid = undefined;
        var noise_ci: [sp_noise_blobs]usize = undefined; // index into contents[]
        {
            var n: usize = 0;
            while (n < sp_noise_blobs) : (n += 1) {
                var nb: std.ArrayList(u8) = .empty;
                errdefer nb.deinit(gpa);
                const rows = 40 + rand.uintLessThan(usize, 40);
                var j: usize = 0;
                while (j < rows) : (j += 1) try nb.print(gpa, "noise {d} row {d}\n", .{ n, j });
                const nbytes = try nb.toOwnedSlice(gpa);
                var key: [32]u8 = undefined;
                std.crypto.hash.sha3.Sha3_256.hash(nbytes, &key, .{});
                noise_rid[n] = try src.putZlib(&key, nbytes);
                keys[nf] = key;
                contents[nf] = nbytes;
                noise_ci[n] = nf;
                nf += 1;
            }
        }

        const nfiles = sp_min_files + rand.uintLessThan(usize, sp_max_files - sp_min_files + 1);
        const nvers = sp_min_versions + rand.uintLessThan(usize, sp_max_versions - sp_min_versions + 1);

        // Each tracked file gets its OWN random body, shared verbatim across that
        // file's versions (so a same-file version delta is tiny) but independent of
        // every other file's (so a cross-file delta is unprofitable — pack's
        // best-of-N never prefers a chronological neighbor over the same-path
        // predecessor, which the non-vacuity probe below relies on). Length is
        // well above pickBase's cheap length early-out so a base is never skipped.
        var bodies: [sp_max_files][]u8 = undefined;
        var nbodies: usize = 0;
        defer for (bodies[0..nbodies]) |b| gpa.free(b);
        {
            var f: usize = 0;
            while (f < nfiles) : (f += 1) {
                const blen = 200 + rand.uintLessThan(usize, 120);
                const body = try gpa.alloc(u8, blen);
                for (body) |*b| b.* = rand.int(u8);
                bodies[f] = body;
                nbodies += 1;
            }
        }

        var fname_buf: [sp_max_files][16]u8 = undefined;
        var prev_blob_rid: [sp_max_files]logstore.Rid = undefined;
        var prev_name: [64]u8 = undefined;
        var have_prev = false;
        var ci: usize = 0; // global check-in index — a valid distinct day (01..24)
        var forced_wire_done = false;
        // File 0's v0/v1 keys — the non-vacuity probe: v1 is forced to a wire
        // delta over a poor base and v0 sits beyond the chronological window, so
        // pack can only re-base v1 onto v0 through the §6.2 same-path walk.
        var f0v0_key: [32]u8 = undefined;
        var f0v1_key: [32]u8 = undefined;
        var have_f0v1 = false;

        var version: usize = 0;
        while (version < nvers) : (version += 1) {
            var file: usize = 0;
            while (file < nfiles) : (file += 1) {
                const fname = std.fmt.bufPrint(&fname_buf[file], "file{d}.txt", .{file}) catch unreachable;

                // This file's shared body + a per-version trailer: distinct content
                // ⇒ distinct sha3 key, while a same-file version delta stays tiny.
                var bbuf: std.ArrayList(u8) = .empty;
                errdefer bbuf.deinit(gpa);
                try bbuf.appendSlice(gpa, bodies[file]);
                try bbuf.print(gpa, "\ntrailer file {d} version {d}\n", .{ file, version });
                const bbytes = try bbuf.toOwnedSlice(gpa);
                var freed = false;
                errdefer if (!freed) gpa.free(bbytes);
                var bkey: [32]u8 = undefined;
                std.crypto.hash.sha3.Sha3_256.hash(bbytes, &bkey, .{});
                var bname64: [64]u8 = undefined;
                _ = artifact.artifactName(.sha3_256, bbytes, &bname64);

                // Source encoding. Version 0 of each file is FULL (a clean re-delta
                // target); a later version takes a per-seed form, and file 0's
                // first later version is forced to a wire delta so every round
                // exercises the re-basing path over a poor base.
                var blob_rid: logstore.Rid = undefined;
                if (version == 0) {
                    blob_rid = try src.putZlib(&bkey, bbytes);
                } else {
                    const force_wire = !forced_wire_done and file == 0;
                    const variant: u8 = if (force_wire) 0 else rand.uintLessThan(u8, 3);
                    if (force_wire) forced_wire_done = true;
                    switch (variant) {
                        0 => {
                            const pick = rand.uintLessThan(usize, sp_noise_blobs);
                            const raw = try delta.create(gpa, contents[noise_ci[pick]], bbytes);
                            defer gpa.free(raw);
                            const cont = try container.encode(gpa, raw, .default);
                            defer gpa.free(cont);
                            blob_rid = try src.putDeltaContainer(&bkey, noise_rid[pick], cont);
                        },
                        1 => blob_rid = try src.putArtifact(&bkey, bbytes, prev_blob_rid[file]),
                        else => blob_rid = try src.putZlib(&bkey, bbytes),
                    }
                }
                prev_blob_rid[file] = blob_rid;
                if (file == 0 and version == 0) f0v0_key = bkey;
                if (file == 0 and version == 1) {
                    f0v1_key = bkey;
                    have_f0v1 = true;
                }
                keys[nf] = bkey;
                contents[nf] = bbytes;
                freed = true; // contents[] now owns bbytes
                nf += 1;

                // Manifest snapshotting `fname` -> this blob, parented into the
                // shared linear chain. Full form so pack's §6.1 parent hint and
                // §6.2 F-card walk both run over it.
                var ts_buf: [32]u8 = undefined;
                const ts = std.fmt.bufPrint(&ts_buf, "2020-01-{d:0>2}T00:00:00", .{ci + 1}) catch unreachable;
                const parent: ?[]const u8 = if (have_prev) prev_name[0..] else null;
                const mbytes = try spCheckin(gpa, ts, parent, fname, &bname64);
                var mfreed = false;
                errdefer if (!mfreed) gpa.free(mbytes);
                var mkey: [32]u8 = undefined;
                std.crypto.hash.sha3.Sha3_256.hash(mbytes, &mkey, .{});
                _ = try src.putZlib(&mkey, mbytes);
                keys[nf] = mkey;
                contents[nf] = mbytes;
                mfreed = true; // contents[] now owns mbytes
                nf += 1;
                _ = artifact.artifactName(.sha3_256, mbytes, &prev_name);
                have_prev = true;
                ci += 1;
            }
        }
        const trunk_key = prev_name; // the tip check-in's 64-hex name
        var trunk_digest: [32]u8 = undefined;
        _ = std.fmt.hexToBytes(&trunk_digest, &trunk_key) catch unreachable;

        try src.commit();

        // Pack through the REAL transform into a fresh healthy store.
        var pbackend = healthyFile(gpa, rand);
        defer pbackend.deinit();
        var packed_store = try logstore.LogStore.open(gpa, pbackend.storageFile(), 0);
        defer packed_store.deinit(gpa);
        const stats = pack.packLog(gpa, &src, &packed_store, pack.Filter.keep_all, &.{}) catch |e| switch (e) {
            error.OutOfMemory => return error.OutOfMemory,
            error.Storage => return error.OutOfMemory, // a healthy sim never faults; treat as fatal
            error.Corrupt => return error.TestUnexpectedResult, // a §7.7 round-trip failure IS the bug
        };
        try std.testing.expectEqual(nf, stats.artifacts);

        // Decode-all identical pre/post: every modeled artifact reconstructs to
        // its exact input bytes from BOTH the source and the repacked store, and
        // no packed frame is larger on disk than its source frame (§6.1 monotonic;
        // holds absolutely — the bounded corpus keeps every chain below the read
        // cap, so `copySrcFrame`'s deep-chain fallback is never taken).
        for (keys[0..nf], contents[0..nf]) |k, want| {
            const srid = src.lookup(&k).?;
            const sb = (try src.content(gpa, srid)).?;
            defer gpa.free(sb);
            const prid = packed_store.lookup(&k) orelse return error.TestUnexpectedResult;
            const pb = (try packed_store.content(gpa, prid)).?;
            defer gpa.free(pb);
            try std.testing.expectEqualSlices(u8, want, sb);
            try std.testing.expectEqualSlices(u8, want, pb);
            try std.testing.expect(packed_store.frameSpanOf(prid) <= src.frameSpanOf(srid));
        }
        // The trunk tip check-in survives the pack (a dropped trunk is a bug).
        try std.testing.expect(packed_store.lookup(&trunk_digest) != null);
        try std.testing.expect(stats.bytes_after <= stats.bytes_before);

        // Non-vacuity: file 0's version-1 blob was stored as a verbatim wire delta
        // over a POOR noise base, and its ideal base (version 0) sits beyond the
        // bounded chronological window (≥ 2·(files-1) frames back). So it can pack
        // as a compact delta ONLY if the §6.2 same-path manifest walk offered
        // version 0. Assert pack re-based it onto exactly that same-path
        // predecessor — proof the step-4 lane fired, not that the frame packed full.
        if (have_f0v1) {
            const v1_rid = packed_store.lookup(&f0v1_key).?;
            try std.testing.expectEqual(logstore.FrameKind.delta, packed_store.kindOf(v1_rid));
            var w = (try packed_store.wire(gpa, v1_rid)).?;
            defer w.deinit(gpa);
            try std.testing.expectEqualSlices(u8, &f0v0_key, w.delta.baseHash());
        }
    }
}

/// §E — putConfig then readConfig round-trips hash_policy, branch, and project
/// id. readConfig drives the file-private parseConfig; config strings are
/// length-prefixed, so arbitrary bytes survive the round-trip.
///
/// No reachability assertion: config strings are length-prefixed, so every
/// round is a put/read round-trip whose only outcome is success — no reject arm
/// to partition.
pub fn parseConfig(gpa: std.mem.Allocator, seed: u64, rounds: usize) !void {
    var prng = std.Random.DefaultPrng.init(seed);
    const rand = prng.random();
    const max_str: usize = 32; // <= logstore.max_config_str
    var branch_buf: [max_str]u8 = undefined;
    var pid_buf: [max_str]u8 = undefined;
    var round: usize = 0;
    while (round < rounds) : (round += 1) {
        var backend = healthyFile(gpa, rand);
        defer backend.deinit();
        var store = try logstore.LogStore.open(gpa, backend.storageFile(), 0);
        defer store.deinit(gpa);

        const blen = rand.uintLessThan(usize, max_str + 1);
        for (branch_buf[0..blen]) |*b| b.* = rand.int(u8);
        const plen = rand.uintLessThan(usize, max_str + 1);
        for (pid_buf[0..plen]) |*b| b.* = rand.int(u8);
        const cfg: logstore.Config = .{
            .hash_policy = rand.int(u8),
            .default_branch = branch_buf[0..blen],
            .project_id = pid_buf[0..plen],
        };

        try store.putConfig(cfg);
        var oc = (try store.readConfig(gpa)).?;
        defer oc.deinit(gpa);
        try std.testing.expectEqual(cfg.hash_policy, oc.config.hash_policy);
        try std.testing.expectEqualSlices(u8, cfg.default_branch, oc.config.default_branch);
        try std.testing.expectEqualSlices(u8, cfg.project_id, oc.config.project_id);
    }
}

// Fixed-seed smoke tests: each delegates to its pub fn at a small round count so
// the invariant runs under `zig build test`; deep runs pass `--rounds`.

test "logstore fuzz: open never crashes on trailing garbage (smoke)" {
    try openGarbage(std.testing.allocator, 0xC0_FFEE, 32);
}

test "logstore §C/sync §4.1 fuzz: putZlib content round-trip (smoke)" {
    try zlibRoundTrip(std.testing.allocator, 0x21B_2117, 32);
}

test "logstore §C/delta §4 fuzz: putDelta content round-trip (smoke)" {
    try deltaRoundTrip(std.testing.allocator, 0xDE17A_04, 32);
}

test "logstore §5 fuzz: pickBase/putArtifact content round-trip + accept invariants (smoke)" {
    try pickBaseRoundTrip(std.testing.allocator, 0xB43E_5EED, 64);
}

test "logstore §6.1 fuzz: pack-redeltify of a mixed-frame store decode-all round-trip (smoke)" {
    try packRoundTrip(std.testing.allocator, 0xC0DE_F022, 48);
}

test "logstore §6.2 fuzz: same-path (multi-file interleaved) pack-redeltify decode-all round-trip (smoke)" {
    try packSamePathRoundTrip(std.testing.allocator, 0x5A3E_F022, 24);
}

test "logstore §E fuzz: putConfig/readConfig round-trip (smoke)" {
    try parseConfig(std.testing.allocator, 0xC0_F1_60, 32);
}