lib/choir/src/product/revision/store.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

   1 const std = @import("std");
   2 const simd = @import("simd");
   3 const revision = @import("root.zig");
   4 const record = revision.record;
   5 const receipt = revision.receipt;
   6 
   7 const Bytes = simd.ScalableTag(u8);
   8 
   9 pub const Event = struct {
  10     store_epoch: u64,
  11     counter: u64,
  12     parent: ?ParentEvent,
  13 };
  14 
  15 pub const ParentEvent = struct { store_epoch: u64, counter: u64 };
  16 
  17 pub const Limits = struct {
  18     revisions: u32,
  19     kinds: u32,
  20     builders: u32,
  21     compiler_manifests: u32,
  22     record_bytes: u32,
  23     gate_scratch_bytes: u32,
  24     candidate_count: u32,
  25     screening_bytes: u32,
  26 };
  27 
  28 /// The compiler manifest is owner-interned and arrives beside the record, since
  29 /// no record carries the compiler that produced it.
  30 pub const GateInput = struct {
  31     exact: record.Exact,
  32     compiler_manifest: []const u8,
  33     dependencies: []const record.Dependency,
  34 };
  35 
  36 pub const Gate = struct {
  37     identity: record.Version,
  38     definition: []const u8,
  39     scratch_bytes: u32,
  40     run: *const fn (GateInput, []u8) anyerror!record.EntityCounts,
  41 };
  42 
  43 pub const KindContract = struct {
  44     identity: record.Version,
  45     schema: Gate,
  46     gates: []const Gate,
  47 };
  48 
  49 pub const Dependency = struct {
  50     role: []const u8,
  51     revision: *const Revision,
  52 };
  53 
  54 pub const Request = struct {
  55     kind: *const Kind,
  56     address: record.Address,
  57     inputs: record.Inputs,
  58     dependencies: []const Dependency = &.{},
  59     parent: ?*const Revision = null,
  60     expected_image: ?[]const u8 = null,
  61 };
  62 
  63 pub const View = struct {
  64     exact: record.Exact,
  65     compiler_manifest: []const u8,
  66     semantic_record: []const u8,
  67     digest: [32]u8,
  68     bucket: u64,
  69     event: Event,
  70     entities: record.EntityCounts,
  71     work: receipt.WorkReceiptV1,
  72     gate_manifest: []const u8,
  73 };
  74 
  75 /// Exact transport metadata has no publication, gate, entity or reuse authority.
  76 /// Retaining this handle keeps the store's immutable record allocation alive.
  77 pub const Record = opaque {
  78     pub fn retain(self: *const Record) !*const Record {
  79         try recordData(self).owner.retain();
  80         return self;
  81     }
  82 
  83     pub fn release(self: *const Record) void {
  84         recordData(self).owner.release();
  85     }
  86 
  87     pub fn bytes(self: *const Record) []const u8 {
  88         return recordData(self).semantic;
  89     }
  90 
  91     pub fn view(self: *const Record) record.Exact {
  92         return recordData(self).exact;
  93     }
  94 
  95     pub fn address(self: *const Record) record.Address {
  96         return record.decodeAddress(self.view().address) catch unreachable;
  97     }
  98 
  99     pub fn inputs(self: *const Record) record.InputView {
 100         return record.decodeInputs(self.view().inputs) catch unreachable;
 101     }
 102 
 103     /// The owner-interned bytes this record was admitted under.
 104     pub fn compilerManifest(self: *const Record) []const u8 {
 105         return recordData(self).compiler_manifest;
 106     }
 107 
 108     pub fn eql(self: *const Record, other: *const Record) bool {
 109         return sameIdentity(recordData(self), recordData(other));
 110     }
 111 
 112     pub fn bucket(self: *const Record) u64 {
 113         const value = recordData(self).owner.digest_fn(self.view().image);
 114         return std.mem.readInt(u64, value[0..8], .little);
 115     }
 116 };
 117 
 118 /// This reference owns one retain on the revision's storage allocation.
 119 pub const Entity = struct {
 120     revision: *const Revision,
 121     namespace: record.Namespace,
 122     ordinal: u32,
 123 
 124     pub fn release(self: Entity) void {
 125         self.revision.release();
 126     }
 127 
 128     pub fn eql(self: Entity, other: Entity) bool {
 129         return self.namespace == other.namespace and self.ordinal == other.ordinal and
 130             self.revision.eql(other.revision);
 131     }
 132 };
 133 
 134 pub const Revision = opaque {
 135     /// The returned reference is borrowed from this sealed revision. One handle
 136     /// stands for one record under one compiler, so a revision whose bytes a
 137     /// foreign compiler also produced still answers under its own.
 138     pub fn metadata(self: *const Revision) *const Record {
 139         const value = entry(self);
 140         return @ptrCast(value.owner.findRecordUnder(value.semantic, value.compiler_manifest).?);
 141     }
 142 
 143     pub fn retain(self: *const Revision) !*const Revision {
 144         try entry(self).owner.retain();
 145         return self;
 146     }
 147 
 148     pub fn release(self: *const Revision) void {
 149         entry(self).owner.release();
 150     }
 151 
 152     pub fn view(self: *const Revision) View {
 153         return entry(self).view();
 154     }
 155 
 156     pub fn eql(self: *const Revision, other: *const Revision) bool {
 157         return sameIdentity(&entry(self).metadata, &entry(other).metadata);
 158     }
 159 
 160     pub fn address(self: *const Revision) record.Address {
 161         return record.decodeAddress(entry(self).exact.address) catch unreachable;
 162     }
 163 
 164     pub fn inputs(self: *const Revision) record.InputView {
 165         return record.decodeInputs(entry(self).exact.inputs) catch unreachable;
 166     }
 167 
 168     pub fn requireDependency(
 169         self: *const Revision,
 170         role: []const u8,
 171         input: *const Revision,
 172     ) error{UndeclaredProductInput}!void {
 173         const value = entry(self);
 174         const declared = self.inputs().dependencies;
 175         std.debug.assert(value.references.len == declared.count);
 176         var dependencies = declared.iterator();
 177         for (value.references) |reference| {
 178             const dependency = (dependencies.next() catch unreachable).?;
 179             if (!std.mem.eql(u8, dependency.role, role)) continue;
 180             if (simd.equal(Bytes, reference, input.view().semantic_record)) return;
 181         }
 182         return error.UndeclaredProductInput;
 183     }
 184 
 185     pub fn entity(self: *const Revision, namespace: record.Namespace, ordinal: u32) !Entity {
 186         if (ordinal >= entry(self).entities[@backingInt(namespace)]) return error.InvalidEntity;
 187         return .{ .revision = try self.retain(), .namespace = namespace, .ordinal = ordinal };
 188     }
 189 
 190     pub fn requireGates(self: *const Revision, required: []const record.Version) !void {
 191         const kind = entry(self).kind;
 192         for (required) |identity| {
 193             if (kind.schema.identity.eql(identity)) continue;
 194             for (kind.gates) |gate| {
 195                 if (gate.identity.eql(identity)) break;
 196             } else return error.MissingGateEvidence;
 197         }
 198     }
 199 };
 200 
 201 pub const Kind = opaque {};
 202 
 203 pub const Store = opaque {
 204     pub fn create(allocator: std.mem.Allocator, limits: Limits) !*Store {
 205         return Storage.create(allocator, limits);
 206     }
 207 
 208     pub fn release(self: *Store) void {
 209         storage(self).release();
 210     }
 211 
 212     /// Copies and structurally validates restored metadata under explicit bounds.
 213     /// A matching record is interned, but this operation never creates a Revision.
 214     /// No record names its compiler, so the caller states which one produced these
 215     /// bytes and the store interns it exactly as it interns a draft's.
 216     pub fn importRecord(
 217         self: *Store,
 218         bytes: []const u8,
 219         compiler_manifest: []const u8,
 220         bounds: record.ClosureBounds,
 221     ) !*const Record {
 222         return storage(self).importRecord(bytes, compiler_manifest, bounds);
 223     }
 224 
 225     pub fn register(self: *Store, contract: KindContract) !*const Kind {
 226         return storage(self).register(contract);
 227     }
 228 
 229     pub fn freeze(self: *Store) void {
 230         std.debug.assert(!storage(self).frozen);
 231         storage(self).frozen = true;
 232     }
 233 
 234     pub fn begin(self: *Store, request: Request, limits: receipt.Limits) !*Builder {
 235         return Draft.create(storage(self), request, limits);
 236     }
 237 
 238     /// Candidates are borrowed until store release; lookup grants no reuse authority.
 239     pub fn lookup(
 240         self: *Store,
 241         bucket_hint: u64,
 242         output: []*const Revision,
 243     ) []const *const Revision {
 244         const state = storage(self);
 245         const bound = @min(output.len, state.limits.candidate_count);
 246         var count: usize = 0;
 247         for (state.entries[0..state.count]) |candidate| {
 248             if (count == bound) break;
 249             if (candidate.bucket != bucket_hint) continue;
 250             if (candidate.semantic.len > state.limits.screening_bytes) continue;
 251             output[count] = @ptrCast(candidate);
 252             count += 1;
 253         }
 254         return output[0..count];
 255     }
 256 
 257     pub fn publicationCount(self: *const Store) u32 {
 258         const state: *const Storage = @ptrCast(@alignCast(self));
 259         return state.count;
 260     }
 261 };
 262 
 263 pub const State = enum { open, captured, gated, sealed, aborted };
 264 
 265 pub const Builder = opaque {
 266     /// The lease keeps unpublished working bytes alive independently of this builder.
 267     pub fn acquireWorkspace(self: *Builder, region: WorkspaceRegion) !WorkspaceLease {
 268         const state = draft(self);
 269         if (state.state != .open) return error.InvalidBuilderState;
 270         if (state.work.view().outcome != .running) return error.TerminalWorkOutcome;
 271         return state.workspace.?.acquire(region);
 272     }
 273 
 274     /// A live lease binds producer storage to the request that reserved it.
 275     pub fn ownsWorkspace(self: *Builder, lease: WorkspaceLease) bool {
 276         const state = draft(self);
 277         std.debug.assert(state.state == .open);
 278         return state.workspace == workspaceData(lease.owner);
 279     }
 280 
 281     pub fn inputs(self: *Builder) record.InputView {
 282         const state = draft(self);
 283         std.debug.assert(state.state == .open);
 284         return record.decodeInputs(state.inputs) catch unreachable;
 285     }
 286 
 287     /// The owner-interned bytes this draft was admitted under.
 288     pub fn compilerManifest(self: *Builder) []const u8 {
 289         const state = draft(self);
 290         std.debug.assert(state.state == .open);
 291         return state.compiler_manifest;
 292     }
 293 
 294     pub fn accounting(self: *Builder) *receipt.AccountingV1 {
 295         std.debug.assert(draft(self).state == .open);
 296         return draft(self).work;
 297     }
 298 
 299     pub fn requireDependency(self: *Builder, role: []const u8, input: *const Revision) !void {
 300         const state = draft(self);
 301         errdefer state.work.fail(.rejected);
 302         if (state.state != .open) return error.InvalidBuilderState;
 303         if (state.work.view().outcome != .running) return error.TerminalWorkOutcome;
 304         for (state.dependencies) |dependency| {
 305             if (!std.mem.eql(u8, dependency.role, role)) continue;
 306             if (simd.equal(Bytes, dependency.exact, input.view().semantic_record)) return;
 307         }
 308         return error.UndeclaredProductInput;
 309     }
 310 
 311     pub fn capture(self: *Builder, bytes: []const u8, observations: []const record.Fact) !void {
 312         errdefer draft(self).work.fail(.rejected);
 313         try draft(self).capture(bytes, observations);
 314     }
 315 
 316     pub fn seal(self: *Builder, kind: *const Kind) !*const Revision {
 317         errdefer draft(self).work.fail(.rejected);
 318         return draft(self).seal(kind);
 319     }
 320 
 321     /// A mismatch is screened before compiler obligations. Exhaustion is terminal.
 322     pub fn admitReuse(self: *Builder, candidate: *const Revision) !?Reuse {
 323         errdefer draft(self).work.fail(.rejected);
 324         return draft(self).admitReuse(candidate);
 325     }
 326 
 327     /// A matching restored record only binds a comparison against fresh cold work.
 328     /// It cannot authorize replay; capture must reproduce its complete image.
 329     /// Restored bytes do not name their compiler, so the caller states which one
 330     /// produced them and a draft admitted under another compiler declines.
 331     pub fn screenRestored(
 332         self: *Builder,
 333         bytes: []const u8,
 334         compiler_manifest: []const u8,
 335     ) !bool {
 336         errdefer draft(self).work.fail(.rejected);
 337         return draft(self).screenRestored(bytes, compiler_manifest);
 338     }
 339 
 340     pub fn abort(self: *Builder, outcome: receipt.Outcome) ?Failure {
 341         const state = draft(self);
 342         std.debug.assert(state.state != .sealed);
 343         std.debug.assert(state.state != .aborted);
 344         state.work.fail(outcome);
 345         const failure = Failure.capture(state) catch null;
 346         state.state = .aborted;
 347         state.destroy();
 348         return failure;
 349     }
 350 };
 351 
 352 pub const WorkspaceRegion = enum { producer, scratch };
 353 pub const Workspace = opaque {};
 354 
 355 /// Exclusive mutable byte storage; it never becomes a revision view.
 356 pub const WorkspaceLease = struct {
 357     owner: *Workspace,
 358     region: WorkspaceRegion,
 359 
 360     pub fn bytes(self: WorkspaceLease) []u8 {
 361         const state = workspaceData(self.owner);
 362         std.debug.assert(state.leased[@backingInt(self.region)]);
 363         const boundary = state.bytes.len - state.scratch_bytes;
 364         return switch (self.region) {
 365             .producer => state.bytes[0..boundary],
 366             .scratch => state.bytes[boundary..],
 367         };
 368     }
 369 
 370     pub fn release(self: WorkspaceLease) void {
 371         const state = workspaceData(self.owner);
 372         const active = &state.leased[@backingInt(self.region)];
 373         std.debug.assert(active.*);
 374         active.* = false;
 375         state.release();
 376     }
 377 };
 378 
 379 const WorkspaceData = struct {
 380     allocator: std.mem.Allocator,
 381     bytes: []u8,
 382     scratch_bytes: u32,
 383     references: u32 = 1,
 384     leased: [2]bool = @splat(false),
 385 
 386     fn acquire(self: *WorkspaceData, region: WorkspaceRegion) !WorkspaceLease {
 387         const active = &self.leased[@backingInt(region)];
 388         if (active.*) return error.WorkspaceAlreadyLeased;
 389         std.debug.assert(self.references < 3);
 390         self.references += 1;
 391         active.* = true;
 392         return .{ .owner = @ptrCast(self), .region = region };
 393     }
 394 
 395     fn release(self: *WorkspaceData) void {
 396         std.debug.assert(self.references > 0);
 397         self.references -= 1;
 398         if (self.references != 0) return;
 399         std.debug.assert(!self.leased[0]);
 400         std.debug.assert(!self.leased[1]);
 401         const allocator = self.allocator;
 402         releaseUntouched(allocator, self.bytes);
 403         allocator.destroy(self);
 404     }
 405 };
 406 
 407 fn workspaceData(handle: *Workspace) *WorkspaceData {
 408     return @ptrCast(@alignCast(handle));
 409 }
 410 
 411 pub const Reuse = struct {
 412     allocator: std.mem.Allocator,
 413     revision: *const Revision,
 414     work: receipt.WorkReceiptV1,
 415 
 416     pub fn deinit(self: *Reuse) void {
 417         self.revision.release();
 418         self.allocator.free(self.work.events);
 419         self.* = undefined;
 420     }
 421 };
 422 
 423 pub const Failure = struct {
 424     allocator: std.mem.Allocator,
 425     address: []const u8,
 426     inputs: []const u8,
 427     work: receipt.WorkReceiptV1,
 428 
 429     fn capture(state: *const Draft) !Failure {
 430         const allocator = state.owner.allocator;
 431         const address = try allocator.dupe(u8, state.address);
 432         errdefer allocator.free(address);
 433         const inputs = try allocator.dupe(u8, state.inputs);
 434         errdefer allocator.free(inputs);
 435         var work = state.work.view();
 436         work.events = try allocator.dupe(receipt.Event, work.events);
 437         return .{ .allocator = allocator, .address = address, .inputs = inputs, .work = work };
 438     }
 439 
 440     pub fn deinit(self: *Failure) void {
 441         self.allocator.free(self.address);
 442         self.allocator.free(self.inputs);
 443         self.allocator.free(self.work.events);
 444         self.* = undefined;
 445     }
 446 };
 447 
 448 var next_epoch = std.atomic.Value(u64).init(1);
 449 
 450 const Storage = struct {
 451     allocator: std.mem.Allocator,
 452     limits: Limits,
 453     epoch: u64,
 454     references: u64 = 1,
 455     entries: []*Entry,
 456     count: u32 = 0,
 457     records: []*RecordData,
 458     record_count: u32 = 0,
 459     kinds: []*KindData,
 460     kind_count: u32 = 0,
 461     manifests: [][]u8,
 462     manifest_count: u32 = 0,
 463     builder_count: u32 = 0,
 464     event_counter: u64 = 0,
 465     frozen: bool = false,
 466     digest_fn: *const fn ([]const u8) [32]u8 = digest,
 467 
 468     fn create(allocator: std.mem.Allocator, limits: Limits) !*Store {
 469         if (limits.revisions == 0 or limits.kinds == 0 or limits.builders == 0 or
 470             limits.record_bytes == 0 or limits.candidate_count == 0 or
 471             limits.compiler_manifests == 0)
 472         {
 473             return error.InvalidStoreLimits;
 474         }
 475         const self = try allocator.create(Storage);
 476         errdefer allocator.destroy(self);
 477         const entries = try allocator.alloc(*Entry, limits.revisions);
 478         errdefer allocator.free(entries);
 479         const records = try allocator.alloc(*RecordData, limits.revisions);
 480         errdefer allocator.free(records);
 481         const kinds = try allocator.alloc(*KindData, limits.kinds);
 482         errdefer allocator.free(kinds);
 483         const manifests = try allocator.alloc([]u8, limits.compiler_manifests);
 484         errdefer allocator.free(manifests);
 485         self.* = .{
 486             .allocator = allocator,
 487             .limits = limits,
 488             .epoch = try allocateEpoch(),
 489             .entries = entries,
 490             .records = records,
 491             .kinds = kinds,
 492             .manifests = manifests,
 493         };
 494         return @ptrCast(self);
 495     }
 496 
 497     /// Returns this store's copy of the given compiler manifest, admitting a new
 498     /// one only while the declared capacity has room. Interned bytes live until
 499     /// the store dies, because sealed records reference them and never re-copy.
 500     fn internManifest(self: *Storage, bytes: []const u8) ![]const u8 {
 501         std.debug.assert(self.manifest_count <= self.manifests.len);
 502         if (bytes.len == 0) return error.MissingCompilerManifest;
 503         if (bytes.len > self.limits.record_bytes) return error.RecordLimit;
 504         for (self.manifests[0..self.manifest_count]) |existing| {
 505             if (simd.equal(Bytes, existing, bytes)) return existing;
 506         }
 507         if (self.manifest_count == self.manifests.len) return error.CompilerManifestLimit;
 508         const copy = try self.allocator.dupe(u8, bytes);
 509         self.manifests[self.manifest_count] = copy;
 510         self.manifest_count += 1;
 511         return copy;
 512     }
 513 
 514     fn retain(self: *Storage) !void {
 515         self.references = std.math.add(u64, self.references, 1) catch {
 516             return error.ReferenceOverflow;
 517         };
 518     }
 519 
 520     fn release(self: *Storage) void {
 521         std.debug.assert(self.references > 0);
 522         self.references -= 1;
 523         if (self.references != 0) return;
 524         std.debug.assert(self.builder_count == 0);
 525         const allocator = self.allocator;
 526         for (self.entries[0..self.count]) |item| item.destroy();
 527         for (self.records[0..self.record_count]) |item| item.destroy();
 528         for (self.kinds[0..self.kind_count]) |kind| kind.destroy();
 529         for (self.manifests[0..self.manifest_count]) |manifest| allocator.free(manifest);
 530         allocator.free(self.entries);
 531         allocator.free(self.records);
 532         allocator.free(self.kinds);
 533         allocator.free(self.manifests);
 534         allocator.destroy(self);
 535     }
 536 
 537     /// Finds equal bytes regardless of compiler, which is what sharing one
 538     /// immutable buffer needs. Identity asks `findRecordUnder` instead.
 539     fn findRecord(self: *Storage, bytes: []const u8) ?*const RecordData {
 540         for (self.records[0..self.record_count]) |item| {
 541             if (simd.equal(Bytes, item.semantic, bytes)) return item;
 542         }
 543         for (self.entries[0..self.count]) |item| {
 544             if (simd.equal(Bytes, item.semantic, bytes)) return &item.metadata;
 545         }
 546         return null;
 547     }
 548 
 549     /// Every record this store holds names a manifest this store interned, so
 550     /// equal manifests are one address and the screen costs a pointer compare.
 551     fn findRecordUnder(
 552         self: *Storage,
 553         bytes: []const u8,
 554         manifest: []const u8,
 555     ) ?*const RecordData {
 556         for (self.records[0..self.record_count]) |item| {
 557             if (item.compiler_manifest.ptr != manifest.ptr) continue;
 558             if (simd.equal(Bytes, item.semantic, bytes)) return item;
 559         }
 560         for (self.entries[0..self.count]) |item| {
 561             if (item.metadata.compiler_manifest.ptr != manifest.ptr) continue;
 562             if (simd.equal(Bytes, item.semantic, bytes)) return &item.metadata;
 563         }
 564         return null;
 565     }
 566 
 567     fn importRecord(
 568         self: *Storage,
 569         bytes: []const u8,
 570         compiler_manifest: []const u8,
 571         bounds: record.ClosureBounds,
 572     ) !*const Record {
 573         if (bytes.len > self.limits.record_bytes) return error.RecordLimit;
 574         if (bytes.len > bounds.bytes) return error.RecordLimit;
 575         const interned = try self.internManifest(compiler_manifest);
 576         const copy = try self.allocator.dupe(u8, bytes);
 577         errdefer self.allocator.free(copy);
 578         try record.validateClosure(copy, bounds);
 579         if (self.findRecordUnder(copy, interned)) |existing| {
 580             try self.retain();
 581             self.allocator.free(copy);
 582             return @ptrCast(existing);
 583         }
 584         if (self.record_count == self.records.len) return error.RecordCountLimit;
 585         const metadata = try self.allocator.create(RecordData);
 586         errdefer self.allocator.destroy(metadata);
 587         metadata.* = .{
 588             .owner = self,
 589             .compiler_manifest = interned,
 590             .semantic = copy,
 591             .exact = record.decodeExact(copy) catch unreachable,
 592         };
 593         try self.retain();
 594         self.records[self.record_count] = metadata;
 595         self.record_count += 1;
 596         return @ptrCast(metadata);
 597     }
 598 
 599     fn register(self: *Storage, contract: KindContract) !*const Kind {
 600         if (self.frozen) return error.RegistrationFrozen;
 601         if (contract.schema.scratch_bytes > self.limits.gate_scratch_bytes) {
 602             return error.GateScratchLimit;
 603         }
 604         for (contract.gates) |gate| {
 605             if (gate.scratch_bytes > self.limits.gate_scratch_bytes) return error.GateScratchLimit;
 606         }
 607         const manifest = try encodeManifest(self.allocator, contract);
 608         errdefer self.allocator.free(manifest);
 609         if (manifest.len > self.limits.record_bytes) return error.RecordLimit;
 610         for (self.kinds[0..self.kind_count]) |existing| {
 611             if (!existing.identity.eql(contract.identity)) continue;
 612             if (!std.mem.eql(u8, existing.manifest, manifest) or
 613                 !existing.sameCallbacks(contract)) return error.KindContractMismatch;
 614             self.allocator.free(manifest);
 615             return @ptrCast(existing);
 616         }
 617         if (self.kind_count == self.kinds.len) return error.KindLimit;
 618         const kind = try KindData.create(self, contract, manifest);
 619         self.kinds[self.kind_count] = kind;
 620         self.kind_count += 1;
 621         return @ptrCast(kind);
 622     }
 623 };
 624 
 625 const KindData = struct {
 626     owner: *Storage,
 627     identity: record.Version,
 628     manifest: []u8,
 629     schema: Gate,
 630     gates: []Gate,
 631 
 632     fn create(owner: *Storage, contract: KindContract, manifest: []u8) !*KindData {
 633         const allocator = owner.allocator;
 634         const self = try allocator.create(KindData);
 635         errdefer allocator.destroy(self);
 636         const name = try allocator.dupe(u8, contract.identity.name);
 637         errdefer allocator.free(name);
 638         const schema = try cloneGate(allocator, contract.schema);
 639         errdefer freeGate(allocator, schema);
 640         const gates = try allocator.alloc(Gate, contract.gates.len);
 641         errdefer allocator.free(gates);
 642         var count: usize = 0;
 643         errdefer for (gates[0..count]) |gate| freeGate(allocator, gate);
 644         for (contract.gates, gates) |gate, *copy| {
 645             copy.* = try cloneGate(allocator, gate);
 646             count += 1;
 647         }
 648         self.* = .{
 649             .owner = owner,
 650             .identity = .{ .name = name, .version = contract.identity.version },
 651             .manifest = manifest,
 652             .schema = schema,
 653             .gates = gates,
 654         };
 655         return self;
 656     }
 657 
 658     fn sameCallbacks(self: *const KindData, contract: KindContract) bool {
 659         if (self.schema.run != contract.schema.run) return false;
 660         if (self.gates.len != contract.gates.len) return false;
 661         for (self.gates, contract.gates) |first, second| {
 662             if (first.run != second.run) return false;
 663         }
 664         return true;
 665     }
 666 
 667     fn destroy(self: *KindData) void {
 668         const allocator = self.owner.allocator;
 669         allocator.free(self.identity.name);
 670         allocator.free(self.manifest);
 671         freeGate(allocator, self.schema);
 672         for (self.gates) |gate| freeGate(allocator, gate);
 673         allocator.free(self.gates);
 674         allocator.destroy(self);
 675     }
 676 };
 677 
 678 const Entry = struct {
 679     owner: *Storage,
 680     metadata: RecordData,
 681     compiler_manifest: []const u8,
 682     semantic: []const u8,
 683     allocation: ?[]u8,
 684     references: []const []const u8,
 685     exact: record.Exact,
 686     digest_value: [32]u8,
 687     bucket: u64,
 688     event: Event,
 689     entities: record.EntityCounts,
 690     kind: *const KindData,
 691     work: receipt.WorkReceiptV1,
 692 
 693     fn view(self: *const Entry) View {
 694         return .{
 695             .exact = self.exact,
 696             .compiler_manifest = self.compiler_manifest,
 697             .semantic_record = self.semantic,
 698             .digest = self.digest_value,
 699             .bucket = self.bucket,
 700             .event = self.event,
 701             .entities = self.entities,
 702             .work = self.work,
 703             .gate_manifest = self.kind.manifest,
 704         };
 705     }
 706 
 707     fn destroy(self: *Entry) void {
 708         const allocator = self.owner.allocator;
 709         if (self.allocation) |bytes| releaseUntouched(allocator, bytes);
 710         allocator.free(self.references);
 711         allocator.free(self.work.events);
 712         allocator.destroy(self);
 713     }
 714 };
 715 
 716 const Draft = struct {
 717     owner: *Storage,
 718     kind: *const KindData,
 719     compiler_manifest: []const u8,
 720     state: State = .open,
 721     address: []u8,
 722     inputs: []u8,
 723     dependencies: []record.Dependency,
 724     revisions: []*const Revision,
 725     facts: []record.Fact,
 726     expected_image: ?[]u8,
 727     image: ?[]u8 = null,
 728     output: ?[]u8 = null,
 729     workspace: ?*WorkspaceData = null,
 730     parent: ?ParentEvent,
 731     work: *receipt.AccountingV1,
 732     entities: record.EntityCounts = @splat(0),
 733     screened_candidates: u32 = 0,
 734     screened_bytes: u64 = 0,
 735     restored: bool = false,
 736 
 737     fn create(owner: *Storage, request: Request, limits: receipt.Limits) !*Builder {
 738         if (!owner.frozen) return error.RegistrationOpen;
 739         const kind = kindData(request.kind);
 740         if (kind.owner != owner) return error.ForeignKind;
 741         if (owner.builder_count == owner.limits.builders) return error.BuilderLimit;
 742         const input_bound = try inspectRequest(request, owner.limits.record_bytes);
 743         const input_capacity = try requestCapacity(request, input_bound);
 744         const work = try receipt.AccountingV1.create(
 745             owner.allocator,
 746             limits,
 747             request.inputs.pipeline,
 748         );
 749         errdefer work.destroy();
 750         try transport(work, owner.limits);
 751         const output = try reserveOutput(owner, work);
 752         errdefer releaseUntouched(owner.allocator, output);
 753         const workspace = try reserveWorkspace(owner, work);
 754         errdefer workspace.release();
 755         const token = try work.begin(.input, .{
 756             .identity = .{ .name = "revision-input-v1", .version = 1 },
 757             .work = .{ .input_bytes = input_bound, .allocation_capacity = input_capacity },
 758             .workspace = input_capacity,
 759             .retained_storage = input_capacity,
 760         });
 761         const self = try copyRequest(owner, kind, request, work);
 762         errdefer self.freeRequest();
 763         try work.finish(token, .success, .{
 764             .work = .{ .input_bytes = self.address.len + self.inputs.len },
 765         });
 766         try owner.retain();
 767         owner.builder_count += 1;
 768         self.output = output;
 769         self.workspace = workspace;
 770         return @ptrCast(self);
 771     }
 772 
 773     fn copyRequest(
 774         owner: *Storage,
 775         kind: *const KindData,
 776         request: Request,
 777         work: *receipt.AccountingV1,
 778     ) !*Draft {
 779         const allocator = owner.allocator;
 780         const compiler_manifest = try owner.internManifest(request.inputs.compiler_manifest);
 781         const self = try allocator.create(Draft);
 782         errdefer allocator.destroy(self);
 783         const address = try record.encodeAddress(allocator, request.address);
 784         errdefer allocator.free(address);
 785         const revisions = try allocator.alloc(*const Revision, request.dependencies.len);
 786         errdefer allocator.free(revisions);
 787         const dependencies = try retainDependencies(allocator, request.dependencies, revisions);
 788         errdefer freeDependencies(allocator, dependencies, revisions);
 789         const inputs = try record.encodeInputs(
 790             allocator,
 791             request.inputs,
 792             dependencies,
 793             kind.manifest,
 794         );
 795         errdefer allocator.free(inputs);
 796         try recordSize(owner.limits.record_bytes, address.len, inputs.len, 0);
 797         const facts = try copyFacts(allocator, request.inputs.facts);
 798         errdefer freeFacts(allocator, facts);
 799         const expected = if (request.expected_image) |bytes|
 800             try allocator.dupe(u8, bytes)
 801         else
 802             null;
 803         self.* = .{
 804             .owner = owner,
 805             .kind = kind,
 806             .compiler_manifest = compiler_manifest,
 807             .address = address,
 808             .inputs = inputs,
 809             .dependencies = dependencies,
 810             .revisions = revisions,
 811             .facts = facts,
 812             .expected_image = expected,
 813             .parent = if (request.parent) |parent| .{
 814                 .store_epoch = parent.view().event.store_epoch,
 815                 .counter = parent.view().event.counter,
 816             } else null,
 817             .work = work,
 818         };
 819         return self;
 820     }
 821 
 822     fn capture(self: *Draft, bytes: []const u8, observations: []const record.Fact) !void {
 823         if (self.state != .open) return error.InvalidBuilderState;
 824         try self.work.producersComplete();
 825         try recordSize(
 826             self.owner.limits.record_bytes,
 827             self.address.len,
 828             self.inputs.len,
 829             bytes.len,
 830         );
 831         const token = try self.work.begin(.capture, .{
 832             .identity = .{ .name = "revision-capture-v1", .version = 1 },
 833             .work = .{
 834                 .input_bytes = bytes.len,
 835                 .output_bytes = bytes.len,
 836                 .structural_visits = bytes.len,
 837                 .allocation_capacity = bytes.len,
 838             },
 839             .workspace = bytes.len,
 840             .retained_storage = bytes.len,
 841         });
 842         errdefer self.work.finish(token, .rejected, .{}) catch {};
 843         try record.validateObservations(self.facts, observations);
 844         if (self.expected_image) |expected| {
 845             if (!simd.equal(Bytes, bytes, expected)) return error.UnexpectedImage;
 846         }
 847         self.image = try self.owner.allocator.dupe(u8, bytes);
 848         self.state = .captured;
 849         try self.work.finish(token, .success, .{ .work = .{
 850             .input_bytes = bytes.len,
 851             .output_bytes = bytes.len,
 852         } });
 853     }
 854 
 855     fn seal(self: *Draft, kind: *const Kind) !*const Revision {
 856         if (self.state != .captured) return error.InvalidBuilderState;
 857         if (kindData(kind) != self.kind) return error.KindContractMismatch;
 858         try self.work.producersComplete();
 859         self.entities = try self.runGate(self.kind.schema);
 860         for (self.kind.gates) |gate| _ = try self.runGate(gate);
 861         self.state = .gated;
 862         return self.publish();
 863     }
 864 
 865     fn runGate(self: *Draft, gate: Gate) !record.EntityCounts {
 866         const token = try self.work.begin(.gate, .{
 867             .identity = gate.identity,
 868             .work = .{
 869                 .input_bytes = self.inputs.len + self.image.?.len,
 870                 .structural_visits = self.image.?.len,
 871                 .allocation_capacity = gate.scratch_bytes,
 872             },
 873             .workspace = gate.scratch_bytes,
 874         });
 875         errdefer self.work.finish(token, .rejected, .{}) catch {};
 876         const scratch = try self.workspace.?.acquire(.scratch);
 877         defer scratch.release();
 878         const counts = gate.run(.{
 879             .exact = .{ .address = self.address, .inputs = self.inputs, .image = self.image.? },
 880             .compiler_manifest = self.compiler_manifest,
 881             .dependencies = self.dependencies,
 882         }, scratch.bytes()[0..gate.scratch_bytes]) catch |err| {
 883             if (err == error.WorkExhausted) self.work.fail(.exhausted);
 884             return err;
 885         };
 886         try self.work.finish(token, .success, .{ .work = .{
 887             .input_bytes = self.inputs.len + self.image.?.len,
 888         } });
 889         return counts;
 890     }
 891 
 892     fn publish(self: *Draft) !*const Revision {
 893         const owner = self.owner;
 894         if (owner.count == owner.entries.len) return error.StoreFull;
 895         const event_counter = std.math.add(u64, owner.event_counter, 1) catch {
 896             return error.GenerationOverflow;
 897         };
 898         if (owner.references == std.math.maxInt(u64)) return error.ReferenceOverflow;
 899         const length = try record.exactSize(self.address.len, self.inputs.len, self.image.?.len);
 900         const references = try capacityMul(self.dependencies.len, @sizeOf([]const u8));
 901         const events = try capacityMul(self.work.view().events.len + 1, @sizeOf(receipt.Event));
 902         const metadata = try capacityAdd(try capacityAdd(@sizeOf(Entry), references), events);
 903         const token = try self.work.begin(.output, .{
 904             .identity = .{ .name = "revision-output-v1", .version = 1 },
 905             .work = .{
 906                 .input_bytes = length,
 907                 .output_bytes = length,
 908                 .structural_visits = length,
 909                 .allocation_capacity = metadata,
 910             },
 911             .workspace = try capacityAdd(length, metadata),
 912             .retained_storage = metadata,
 913         });
 914         var output_open = true;
 915         errdefer if (output_open) {
 916             self.work.finish(token, .rejected, .{}) catch {};
 917         };
 918         const published = try self.prepareEntry(event_counter);
 919         errdefer published.destroy();
 920         try self.work.finish(token, .success, .{ .work = .{
 921             .input_bytes = length,
 922             .output_bytes = length,
 923         } });
 924         output_open = false;
 925         try self.work.complete();
 926         const event_buffer = published.work.events;
 927         @memcpy(@constCast(event_buffer), self.work.view().events);
 928         published.work = self.work.view();
 929         published.work.events = event_buffer;
 930         owner.references += 1;
 931         owner.entries[owner.count] = published;
 932         owner.count += 1;
 933         owner.event_counter = event_counter;
 934         self.state = .sealed;
 935         self.destroy();
 936         return @ptrCast(published);
 937     }
 938 
 939     fn prepareEntry(self: *Draft, counter: u64) !*Entry {
 940         const owner = self.owner;
 941         const allocator = owner.allocator;
 942         const published = try allocator.create(Entry);
 943         errdefer allocator.destroy(published);
 944         const references = try allocator.alloc([]const u8, self.dependencies.len);
 945         errdefer allocator.free(references);
 946         const semantic = try record.encodeExactInto(self.output.?, .{
 947             .address = self.address,
 948             .inputs = self.inputs,
 949             .image = self.image.?,
 950         });
 951         var work = self.work.view();
 952         work.events = try allocator.dupe(receipt.Event, work.events);
 953         const digest_value = owner.digest_fn(self.image.?);
 954         published.* = .{
 955             .owner = owner,
 956             .metadata = undefined,
 957             .compiler_manifest = self.compiler_manifest,
 958             .semantic = semantic,
 959             .allocation = self.output,
 960             .references = references,
 961             .exact = record.decodeExact(semantic) catch unreachable,
 962             .digest_value = digest_value,
 963             .bucket = std.mem.readInt(u64, digest_value[0..8], .little),
 964             .event = .{ .store_epoch = owner.epoch, .counter = counter, .parent = self.parent },
 965             .entities = self.entities,
 966             .kind = self.kind,
 967             .work = work,
 968         };
 969         self.output = null;
 970         internImage(published);
 971         self.referenceDependencies(published.exact.inputs, references);
 972         published.metadata = .{
 973             .owner = owner,
 974             .compiler_manifest = self.compiler_manifest,
 975             .semantic = published.semantic,
 976             .exact = published.exact,
 977         };
 978         return published;
 979     }
 980 
 981     /// Producer bounds may depend on either exposed workspace region's capacity.
 982     /// A different reservation needs its own cold trace before it can authorize reuse.
 983     fn admitReuse(self: *Draft, candidate: *const Revision) !?Reuse {
 984         if (self.restored) return error.RestoredCandidateRequiresExecution;
 985         const prior = entry(candidate);
 986         if (!try self.screen(prior.semantic.len)) return null;
 987         if (!simd.equal(Bytes, prior.compiler_manifest, self.compiler_manifest)) return null;
 988         if (!simd.equal(Bytes, prior.kind.manifest, self.kind.manifest)) return null;
 989         if (!simd.equal(Bytes, prior.exact.address, self.address)) return null;
 990         if (!self.eqlInputs(prior)) return null;
 991         if (prior.work.limits.workspace != self.work.view().limits.workspace) return null;
 992         if (prior.owner.limits.gate_scratch_bytes != self.owner.limits.gate_scratch_bytes) {
 993             return null;
 994         }
 995         if (self.expected_image) |expected| {
 996             if (!simd.equal(Bytes, expected, prior.exact.image)) return null;
 997         }
 998         try self.work.replay(prior.work, 4);
 999         const allocator = self.owner.allocator;
1000         var work = self.work.view();
1001         work.events = try allocator.dupe(receipt.Event, work.events);
1002         errdefer allocator.free(work.events);
1003         const retained = try candidate.retain();
1004         errdefer retained.release();
1005         try self.work.complete();
1006         work.outcome = .success;
1007         const result = Reuse{
1008             .allocator = allocator,
1009             .revision = retained,
1010             .work = work,
1011         };
1012         self.state = .sealed;
1013         self.destroy();
1014         return result;
1015     }
1016 
1017     fn eqlInputs(self: *const Draft, prior: *const Entry) bool {
1018         const first = prior.exact.inputs;
1019         const second = self.inputs;
1020         if (first.len != second.len) return false;
1021         const embedded = (record.decodeInputs(first) catch unreachable).dependencies;
1022         const requested = (record.decodeInputs(second) catch unreachable).dependencies;
1023         if (embedded.count != requested.count) return false;
1024         std.debug.assert(prior.references.len == embedded.count);
1025         var prior_dependencies = embedded.iterator();
1026         var draft_dependencies = requested.iterator();
1027         var offset: usize = 0;
1028         for (prior.references) |reference| {
1029             const left = (prior_dependencies.next() catch unreachable).?;
1030             const right = (draft_dependencies.next() catch unreachable).?;
1031             const start = @intFromPtr(left.exact.ptr) - @intFromPtr(first.ptr);
1032             if (start != @intFromPtr(right.exact.ptr) - @intFromPtr(second.ptr)) return false;
1033             if (left.exact.len != right.exact.len) return false;
1034             std.debug.assert(offset <= start);
1035             if (!simd.equal(Bytes, first[offset..start], second[offset..start])) return false;
1036             const retained = self.dependencyRevision(right.role);
1037             if (!simd.equal(Bytes, reference, retained.view().semantic_record)) return false;
1038             offset = start + left.exact.len;
1039         }
1040         return simd.equal(Bytes, first[offset..], second[offset..]);
1041     }
1042 
1043     fn referenceDependencies(self: *const Draft, inputs: []const u8, output: [][]const u8) void {
1044         std.debug.assert(output.len == self.dependencies.len);
1045         const declared = (record.decodeInputs(inputs) catch unreachable).dependencies;
1046         std.debug.assert(declared.count == output.len);
1047         var dependencies = declared.iterator();
1048         for (output) |*reference| {
1049             const embedded = (dependencies.next() catch unreachable).?;
1050             const retained = self.dependencyRevision(embedded.role);
1051             reference.* = if (entry(retained).owner == self.owner)
1052                 retained.view().semantic_record
1053             else
1054                 embedded.exact;
1055             std.debug.assert(reference.len == embedded.exact.len);
1056         }
1057     }
1058 
1059     fn dependencyRevision(self: *const Draft, role: []const u8) *const Revision {
1060         for (self.dependencies, self.revisions) |dependency, retained| {
1061             if (std.mem.eql(u8, dependency.role, role)) return retained;
1062         }
1063         unreachable;
1064     }
1065 
1066     fn screen(self: *Draft, length: usize) !bool {
1067         if (self.state != .open) return error.InvalidBuilderState;
1068         const work = self.work.view();
1069         if (work.outcome != .running) return error.TerminalWorkOutcome;
1070         if (work.events.len != 4) return error.CompilerWorkAlreadyStarted;
1071         const limits = self.owner.limits;
1072         if (self.screened_candidates == limits.candidate_count) return false;
1073         if (length > limits.screening_bytes - self.screened_bytes) return false;
1074         self.screened_candidates += 1;
1075         self.screened_bytes += length;
1076         try self.work.observeTransport(length);
1077         return true;
1078     }
1079 
1080     fn screenRestored(self: *Draft, bytes: []const u8, compiler_manifest: []const u8) !bool {
1081         if (self.restored) return error.RestoredCandidateAlreadyBound;
1082         if (!try self.screen(bytes.len)) return false;
1083         if (!simd.equal(Bytes, self.compiler_manifest, compiler_manifest)) return false;
1084         const restored = record.decodeExact(bytes) catch return false;
1085         if (!simd.equal(Bytes, restored.address, self.address) or
1086             !simd.equal(Bytes, restored.inputs, self.inputs)) return false;
1087         if (self.expected_image) |expected| {
1088             if (!simd.equal(Bytes, expected, restored.image)) return false;
1089         } else {
1090             self.expected_image = try self.owner.allocator.dupe(u8, restored.image);
1091         }
1092         self.restored = true;
1093         return true;
1094     }
1095 
1096     fn freeRequest(self: *Draft) void {
1097         const allocator = self.owner.allocator;
1098         allocator.free(self.address);
1099         allocator.free(self.inputs);
1100         freeDependencies(allocator, self.dependencies, self.revisions);
1101         allocator.free(self.revisions);
1102         freeFacts(allocator, self.facts);
1103         if (self.expected_image) |bytes| allocator.free(bytes);
1104         if (self.image) |bytes| allocator.free(bytes);
1105         if (self.output) |bytes| releaseUntouched(allocator, bytes);
1106         if (self.workspace) |workspace| workspace.release();
1107         allocator.destroy(self);
1108     }
1109 
1110     fn destroy(self: *Draft) void {
1111         const owner = self.owner;
1112         self.work.destroy();
1113         self.freeRequest();
1114         std.debug.assert(owner.builder_count > 0);
1115         owner.builder_count -= 1;
1116         owner.release();
1117     }
1118 };
1119 
1120 fn transport(work: *receipt.AccountingV1, limits: Limits) !void {
1121     const token = try work.begin(.transport, .{
1122         .identity = .{ .name = "revision-screen-v1", .version = 1 },
1123         .work = .{
1124             .input_bytes = limits.screening_bytes,
1125             .allocation_capacity = limits.screening_bytes,
1126         },
1127         .workspace = limits.screening_bytes,
1128         .retained_storage = limits.screening_bytes,
1129     });
1130     try work.finish(token, .success, .{});
1131 }
1132 
1133 fn reserveUntouched(allocator: std.mem.Allocator, capacity: usize) error{OutOfMemory}![]u8 {
1134     if (capacity == 0) return allocator.alloc(u8, 0);
1135     const bytes = allocator.rawAlloc(capacity, .of(u8), @returnAddress()) orelse
1136         return error.OutOfMemory;
1137     return bytes[0..capacity];
1138 }
1139 
1140 fn releaseUntouched(allocator: std.mem.Allocator, bytes: []u8) void {
1141     if (bytes.len == 0) return allocator.free(bytes);
1142     allocator.rawFree(bytes, .of(u8), @returnAddress());
1143 }
1144 
1145 fn reserveOutput(owner: *Storage, work: *receipt.AccountingV1) ![]u8 {
1146     const capacity = owner.limits.record_bytes;
1147     const token = try work.begin(.reservation, .{
1148         .identity = .{ .name = "revision-output-reservation-v1", .version = 1 },
1149         .work = .{ .allocation_capacity = capacity },
1150         .workspace = capacity,
1151         .retained_storage = capacity,
1152     });
1153     errdefer work.finish(token, .rejected, .{}) catch {};
1154     const bytes = try reserveUntouched(owner.allocator, capacity);
1155     errdefer releaseUntouched(owner.allocator, bytes);
1156     try work.finish(token, .success, .{ .work = .{ .allocation_capacity = bytes.len } });
1157     return bytes;
1158 }
1159 
1160 fn reserveWorkspace(owner: *Storage, work: *receipt.AccountingV1) !*WorkspaceData {
1161     const capacity = std.math.cast(usize, work.view().limits.workspace) orelse {
1162         work.fail(.exhausted);
1163         return error.WorkOverflow;
1164     };
1165     const scratch = owner.limits.gate_scratch_bytes;
1166     const token = try work.begin(.reservation, .{
1167         .identity = .{ .name = "revision-workspace-reservation-v1", .version = 1 },
1168         .work = .{ .allocation_capacity = capacity },
1169         .workspace = @max(capacity, scratch),
1170         .retained_storage = capacity,
1171     });
1172     errdefer work.finish(token, .rejected, .{}) catch {};
1173     const allocator = owner.allocator;
1174     const state = try allocator.create(WorkspaceData);
1175     errdefer allocator.destroy(state);
1176     const bytes = try reserveUntouched(allocator, capacity);
1177     errdefer releaseUntouched(allocator, bytes);
1178     try work.finish(token, .success, .{ .work = .{ .allocation_capacity = bytes.len } });
1179     state.* = .{ .allocator = allocator, .bytes = bytes, .scratch_bytes = scratch };
1180     return state;
1181 }
1182 
1183 fn internImage(published: *Entry) void {
1184     const owner = published.owner;
1185     if (owner.findRecord(published.semantic)) |existing| {
1186         releaseUntouched(owner.allocator, published.allocation.?);
1187         published.semantic = existing.semantic;
1188         published.exact = existing.exact;
1189         published.allocation = null;
1190     }
1191 }
1192 
1193 /// A revision's identity is its exact bytes under its owner-interned compiler
1194 /// manifest. Manifests intern per store, so revisions that share one meet at a
1195 /// single address and settle in constant time; across stores the bytes decide.
1196 fn sameIdentity(self: *const RecordData, other: *const RecordData) bool {
1197     if (!simd.equal(Bytes, self.compiler_manifest, other.compiler_manifest)) return false;
1198     return self.exact.eql(other.exact);
1199 }
1200 
1201 const RecordData = struct {
1202     owner: *Storage,
1203     compiler_manifest: []const u8,
1204     semantic: []const u8,
1205     exact: record.Exact,
1206 
1207     fn destroy(self: *RecordData) void {
1208         const allocator = self.owner.allocator;
1209         allocator.free(self.semantic);
1210         allocator.destroy(self);
1211     }
1212 };
1213 
1214 fn recordData(handle: *const Record) *const RecordData {
1215     return @ptrCast(@alignCast(handle));
1216 }
1217 
1218 fn retainDependencies(
1219     allocator: std.mem.Allocator,
1220     source: []const Dependency,
1221     revisions: []*const Revision,
1222 ) ![]record.Dependency {
1223     std.debug.assert(source.len == revisions.len);
1224     const result = try allocator.alloc(record.Dependency, source.len);
1225     errdefer allocator.free(result);
1226     var initialized: usize = 0;
1227     errdefer for (result[0..initialized], revisions[0..initialized]) |item, retained| {
1228         allocator.free(item.role);
1229         retained.release();
1230     };
1231     for (source, result, revisions) |dependency, *output, *retained| {
1232         const role = try allocator.dupe(u8, dependency.role);
1233         errdefer allocator.free(role);
1234         retained.* = try dependency.revision.retain();
1235         output.* = .{ .role = role, .exact = retained.*.view().semantic_record };
1236         initialized += 1;
1237     }
1238     return result;
1239 }
1240 
1241 fn freeDependencies(
1242     allocator: std.mem.Allocator,
1243     values: []const record.Dependency,
1244     revisions: []const *const Revision,
1245 ) void {
1246     std.debug.assert(values.len == revisions.len);
1247     for (values, revisions) |value, retained| {
1248         allocator.free(value.role);
1249         retained.release();
1250     }
1251     allocator.free(values);
1252 }
1253 
1254 fn copyFacts(allocator: std.mem.Allocator, source: []const record.Fact) ![]record.Fact {
1255     const result = try allocator.alloc(record.Fact, source.len);
1256     errdefer allocator.free(result);
1257     var initialized: usize = 0;
1258     errdefer for (result[0..initialized]) |item| {
1259         allocator.free(item.key);
1260         if (item.value) |bytes| allocator.free(bytes);
1261     };
1262     for (source, result) |fact, *output| {
1263         const key = try allocator.dupe(u8, fact.key);
1264         errdefer allocator.free(key);
1265         output.* = .{
1266             .key = key,
1267             .value = if (fact.value) |bytes| try allocator.dupe(u8, bytes) else null,
1268         };
1269         initialized += 1;
1270     }
1271     return result;
1272 }
1273 
1274 fn freeFacts(allocator: std.mem.Allocator, values: []const record.Fact) void {
1275     for (values) |value| {
1276         allocator.free(value.key);
1277         if (value.value) |bytes| allocator.free(bytes);
1278     }
1279     allocator.free(values);
1280 }
1281 
1282 fn recordSize(limit: u32, address: usize, inputs: usize, image: usize) !void {
1283     if (try record.exactSize(address, inputs, image) > limit) return error.RecordLimit;
1284 }
1285 
1286 fn inspectRequest(request: Request, limit: u32) !u64 {
1287     var size: u64 = 256;
1288     inline for (@typeInfo(record.Address).@"struct".field_names) |field| {
1289         try addBound(&size, @field(request.address, field).len, limit);
1290     }
1291     try addBound(&size, request.inputs.options.len, limit);
1292     try addBound(&size, request.inputs.policy.len, limit);
1293     try addBound(&size, kindData(request.kind).manifest.len, limit);
1294     for (request.inputs.versions) |version| try addBound(&size, version.name.len + 8, limit);
1295     for (request.inputs.pipeline) |version| try addBound(&size, version.name.len + 8, limit);
1296     for (request.inputs.facts) |fact| {
1297         try addBound(&size, fact.key.len, limit);
1298         try addBound(&size, if (fact.value) |bytes| bytes.len else 0, limit);
1299         try addBound(&size, 9, limit);
1300     }
1301     for (request.dependencies) |dependency| {
1302         try addBound(&size, dependency.role.len, limit);
1303         try addBound(&size, dependency.revision.view().semantic_record.len, limit);
1304         try addBound(&size, 8, limit);
1305     }
1306     if (request.expected_image) |bytes| {
1307         if (bytes.len > limit) return error.RecordLimit;
1308     }
1309     return size;
1310 }
1311 
1312 fn requestCapacity(request: Request, encoded_bound: u64) !u64 {
1313     var size = try capacityMul(encoded_bound, 4);
1314     const tables = [_]struct { count: usize, item_bytes: usize }{
1315         .{ .count = request.inputs.versions.len, .item_bytes = @sizeOf(record.Version) },
1316         .{ .count = request.inputs.facts.len, .item_bytes = 2 * @sizeOf(record.Fact) },
1317         .{ .count = request.dependencies.len, .item_bytes = 2 * @sizeOf(record.Dependency) },
1318         .{ .count = request.dependencies.len, .item_bytes = @sizeOf(*const Revision) },
1319     };
1320     for (tables) |table| {
1321         size = try capacityAdd(size, try capacityMul(table.count, table.item_bytes));
1322     }
1323     size = try capacityAdd(size, @sizeOf(Draft));
1324     if (request.expected_image) |bytes| size = try capacityAdd(size, bytes.len);
1325     return size;
1326 }
1327 
1328 fn capacityAdd(first: u64, second: u64) !u64 {
1329     return std.math.add(u64, first, second) catch error.WorkOverflow;
1330 }
1331 
1332 fn capacityMul(first: u64, second: u64) !u64 {
1333     return std.math.mul(u64, first, second) catch error.WorkOverflow;
1334 }
1335 
1336 fn addBound(size: *u64, additional: usize, limit: u32) !void {
1337     size.* = std.math.add(u64, size.*, additional) catch return error.RecordOverflow;
1338     if (size.* > limit) return error.RecordLimit;
1339 }
1340 
1341 fn allocateEpoch() !u64 {
1342     var expected = next_epoch.load(.monotonic);
1343     for (0..1024) |_| {
1344         if (expected == std.math.maxInt(u64)) return error.GenerationOverflow;
1345         if (next_epoch.cmpxchgWeak(expected, expected + 1, .monotonic, .monotonic)) |actual| {
1346             expected = actual;
1347         } else return expected;
1348     }
1349     return error.EpochContention;
1350 }
1351 
1352 fn cloneGate(allocator: std.mem.Allocator, gate: Gate) !Gate {
1353     const name = try allocator.dupe(u8, gate.identity.name);
1354     errdefer allocator.free(name);
1355     return .{
1356         .identity = .{ .name = name, .version = gate.identity.version },
1357         .definition = try allocator.dupe(u8, gate.definition),
1358         .scratch_bytes = gate.scratch_bytes,
1359         .run = gate.run,
1360     };
1361 }
1362 
1363 fn freeGate(allocator: std.mem.Allocator, gate: Gate) void {
1364     allocator.free(gate.identity.name);
1365     allocator.free(gate.definition);
1366 }
1367 
1368 fn encodeManifest(allocator: std.mem.Allocator, contract: KindContract) ![]u8 {
1369     var writer = record.Writer.init(allocator);
1370     defer writer.deinit();
1371     try writer.writeInt(u32, record.schema_version);
1372     try writeVersion(&writer, contract.identity);
1373     try writeGate(&writer, contract.schema);
1374     try writer.writeCount(contract.gates.len);
1375     for (contract.gates, 0..) |gate, index| {
1376         if (gate.identity.eql(contract.schema.identity)) return error.DuplicateGate;
1377         for (contract.gates[0..index]) |previous| {
1378             if (std.mem.eql(u8, gate.identity.name, previous.identity.name)) {
1379                 return error.DuplicateGate;
1380             }
1381         }
1382         try writeGate(&writer, gate);
1383     }
1384     return writer.finish();
1385 }
1386 
1387 fn writeVersion(writer: *record.Writer, identity: record.Version) !void {
1388     if (identity.version == 0 or identity.name.len == 0) return error.InvalidVersion;
1389     try writer.writeString(identity.name);
1390     try writer.writeInt(u32, identity.version);
1391 }
1392 
1393 fn writeGate(writer: *record.Writer, gate: Gate) !void {
1394     if (gate.definition.len == 0) return error.MissingGateContract;
1395     try writeVersion(writer, gate.identity);
1396     try writer.writeBlob(gate.definition);
1397     try writer.writeInt(u32, gate.scratch_bytes);
1398 }
1399 
1400 fn digest(bytes: []const u8) [32]u8 {
1401     var value: [32]u8 = undefined;
1402     std.crypto.hash.sha2.Sha256.hash(bytes, &value, .{});
1403     return value;
1404 }
1405 
1406 fn storage(handle: *Store) *Storage {
1407     return @ptrCast(@alignCast(handle));
1408 }
1409 
1410 fn entry(handle: *const Revision) *const Entry {
1411     return @ptrCast(@alignCast(handle));
1412 }
1413 
1414 fn kindData(handle: *const Kind) *const KindData {
1415     return @ptrCast(@alignCast(handle));
1416 }
1417 
1418 fn draft(handle: *Builder) *Draft {
1419     return @ptrCast(@alignCast(handle));
1420 }
1421 
1422 const test_limits = Limits{
1423     .revisions = 8,
1424     .kinds = 4,
1425     .builders = 4,
1426     .compiler_manifests = 2,
1427     .record_bytes = 16 * 1024,
1428     .gate_scratch_bytes = 1024,
1429     .candidate_count = 8,
1430     .screening_bytes = 16 * 1024,
1431 };
1432 
1433 const test_work = receipt.Limits{
1434     .allowance = receipt.WorkVector.uniform(4 * 1024 * 1024),
1435     .workspace = 1024 * 1024,
1436     .events = 32,
1437 };
1438 
1439 fn testSchema(input: GateInput, scratch: []u8) !record.EntityCounts {
1440     if (scratch.len < 8) return error.OutOfMemory;
1441     scratch[0] = 0;
1442     if (input.exact.image.len == 0) return error.InvalidImage;
1443     if (input.exact.image[0] != 'v') return error.UnencodableProduct;
1444     var counts: record.EntityCounts = @splat(0);
1445     counts[@backingInt(record.Namespace.root)] = 1;
1446     return counts;
1447 }
1448 
1449 fn testContract() KindContract {
1450     return .{
1451         .identity = .{ .name = "test-kind", .version = 1 },
1452         .schema = .{
1453             .identity = .{ .name = "test-schema", .version = 1 },
1454             .definition = "v prefix; one root",
1455             .scratch_bytes = 8,
1456             .run = testSchema,
1457         },
1458         .gates = &.{},
1459     };
1460 }
1461 
1462 const test_options = "default=expanded";
1463 const test_manifest = "exact compiled inputs";
1464 
1465 fn testRequest(kind: *const Kind) Request {
1466     return .{
1467         .kind = kind,
1468         .address = .{ .producer = "test", .source = "source", .stage = "image", .variant = "" },
1469         .inputs = .{
1470             .compiler_manifest = test_manifest,
1471             .versions = &.{.{ .name = "codec", .version = 1 }},
1472             .pipeline = &.{},
1473             .options = test_options,
1474             .policy = "strict",
1475         },
1476     };
1477 }
1478 
1479 fn testPublish(owner: *Store, kind: *const Kind, bytes: []const u8) !*const Revision {
1480     const builder = try owner.begin(testRequest(kind), test_work);
1481     errdefer if (builder.abort(.rejected)) |failure| {
1482         var owned = failure;
1483         owned.deinit();
1484     };
1485     try builder.capture(bytes, &.{});
1486     return builder.seal(kind);
1487 }
1488 
1489 const TestSuccessor = struct {
1490     kind: *const Kind,
1491     source: *const Revision,
1492     role: []const u8 = "input",
1493     options: []const u8 = test_options,
1494 
1495     fn eqlRequest(left: TestSuccessor, right: TestSuccessor) bool {
1496         return left.kind == right.kind and std.mem.eql(u8, left.role, right.role) and
1497             std.mem.eql(u8, left.options, right.options) and left.source.eql(right.source);
1498     }
1499 };
1500 
1501 fn testBeginSuccessor(owner: *Store, successor: TestSuccessor) !*Builder {
1502     var request = testRequest(successor.kind);
1503     request.inputs.options = successor.options;
1504     const dependencies = [_]Dependency{.{ .role = successor.role, .revision = successor.source }};
1505     request.dependencies = &dependencies;
1506     return owner.begin(request, test_work);
1507 }
1508 
1509 fn testPublishSuccessor(owner: *Store, successor: TestSuccessor) !*const Revision {
1510     const builder = try testBeginSuccessor(owner, successor);
1511     errdefer if (builder.abort(.rejected)) |failure| {
1512         var owned = failure;
1513         owned.deinit();
1514     };
1515     try builder.capture("valid-successor", &.{});
1516     return builder.seal(successor.kind);
1517 }
1518 
1519 const test_closure = record.ClosureBounds{ .bytes = 16 * 1024, .records = 32, .depth = 8 };
1520 
1521 test "revision store interns restored records without publication authority" {
1522     const allocator = std.testing.allocator;
1523     const producer = try Store.create(allocator, test_limits);
1524     const kind = try producer.register(testContract());
1525     producer.freeze();
1526     const published = try testPublish(producer, kind, "value");
1527     const owner = try Store.create(allocator, test_limits);
1528     const first = try owner.importRecord(
1529         published.view().semantic_record,
1530         test_manifest,
1531         test_closure,
1532     );
1533     const second = try owner.importRecord(first.bytes(), test_manifest, test_closure);
1534     try std.testing.expect(first == second);
1535     try std.testing.expect(first.eql(published.metadata()));
1536     try std.testing.expectEqual(@as(u32, 0), owner.publicationCount());
1537     var candidates: [1]*const Revision = undefined;
1538     try std.testing.expectEqual(@as(usize, 0), owner.lookup(first.bucket(), &candidates).len);
1539     producer.release();
1540     published.release();
1541     owner.release();
1542     first.release();
1543     try std.testing.expectEqualStrings("value", second.view().image);
1544     second.release();
1545 }
1546 
1547 test "revision store exact metadata survives forced bucket and digest collisions" {
1548     const owner = try Store.create(std.testing.allocator, test_limits);
1549     defer owner.release();
1550     storage(owner).digest_fn = collidingDigest;
1551     const kind = try owner.register(testContract());
1552     owner.freeze();
1553     const first = try testPublish(owner, kind, "value-a");
1554     defer first.release();
1555     const second = try testPublish(owner, kind, "value-b");
1556     defer second.release();
1557     try std.testing.expectEqual(first.metadata().bucket(), second.metadata().bucket());
1558     try std.testing.expect(!first.metadata().eql(second.metadata()));
1559     const restored = try owner.importRecord(first.metadata().bytes(), test_manifest, test_closure);
1560     defer restored.release();
1561     try std.testing.expect(restored == first.metadata());
1562 }
1563 
1564 fn recordAllocationScenario(allocator: std.mem.Allocator, bytes: []const u8) !void {
1565     const owner = try Store.create(allocator, test_limits);
1566     defer owner.release();
1567     errdefer std.debug.assert(storage(owner).record_count == 0);
1568     const imported = try owner.importRecord(bytes, test_manifest, test_closure);
1569     imported.release();
1570 }
1571 
1572 test "revision store restored record insertion rolls back every allocation failure" {
1573     const owner = try Store.create(std.testing.allocator, test_limits);
1574     defer owner.release();
1575     const kind = try owner.register(testContract());
1576     owner.freeze();
1577     const published = try testPublish(owner, kind, "value");
1578     defer published.release();
1579     try std.testing.checkAllAllocationFailures(
1580         std.testing.allocator,
1581         recordAllocationScenario,
1582         .{published.metadata().bytes()},
1583     );
1584     try std.testing.expectError(error.RecordClosureLimit, owner.importRecord(
1585         published.metadata().bytes(),
1586         test_manifest,
1587         .{ .bytes = test_closure.bytes, .records = 0, .depth = 8 },
1588     ));
1589     try std.testing.expectError(
1590         error.UnknownSchema,
1591         owner.importRecord("invalid", test_manifest, test_closure),
1592     );
1593 }
1594 
1595 test "revision store retains immutable copies after builder and store owner release" {
1596     const owner = try Store.create(std.testing.allocator, test_limits);
1597     const kind = try owner.register(testContract());
1598     owner.freeze();
1599     var original = [_]u8{ 'v', 'a', 'l', 'u', 'e' };
1600     const first = try testPublish(owner, kind, &original);
1601     defer first.release();
1602     const reference = try first.entity(.root, 0);
1603     defer reference.release();
1604     @memset(&original, 'x');
1605     const second = try testPublish(owner, kind, "value");
1606     defer second.release();
1607     try std.testing.expect(first.eql(second));
1608     try std.testing.expect(first.metadata() == second.metadata());
1609     try std.testing.expect(first.view().event.counter != second.view().event.counter);
1610     try std.testing.expectEqual(
1611         first.view().semantic_record.ptr,
1612         second.view().semantic_record.ptr,
1613     );
1614     owner.release();
1615     try std.testing.expectEqualStrings("value", reference.revision.view().exact.image);
1616     try std.testing.expectEqual(.success, first.view().work.outcome);
1617     try std.testing.expectError(error.InvalidEntity, first.entity(.root, 1));
1618 }
1619 
1620 test "revision store sealing after import preserves the canonical metadata handle" {
1621     const producer = try Store.create(std.testing.allocator, test_limits);
1622     defer producer.release();
1623     const producer_kind = try producer.register(testContract());
1624     producer.freeze();
1625     const original = try testPublish(producer, producer_kind, "value");
1626     defer original.release();
1627     const owner = try Store.create(std.testing.allocator, test_limits);
1628     defer owner.release();
1629     const imported = try owner.importRecord(
1630         original.metadata().bytes(),
1631         test_manifest,
1632         test_closure,
1633     );
1634     defer imported.release();
1635     const kind = try owner.register(testContract());
1636     owner.freeze();
1637     const published = try testPublish(owner, kind, "value");
1638     defer published.release();
1639     try std.testing.expect(imported == published.metadata());
1640     try std.testing.expectEqual(@as(u32, 1), owner.publicationCount());
1641 }
1642 
1643 test "revision store metadata answers under its own compiler when bytes collide" {
1644     const producer = try Store.create(std.testing.allocator, test_limits);
1645     defer producer.release();
1646     const producer_kind = try producer.register(testContract());
1647     producer.freeze();
1648     const original = try testPublish(producer, producer_kind, "value");
1649     defer original.release();
1650     const owner = try Store.create(std.testing.allocator, test_limits);
1651     defer owner.release();
1652     const kind = try owner.register(testContract());
1653     owner.freeze();
1654     const published = try testPublish(owner, kind, "value");
1655     defer published.release();
1656     const foreign = try owner.importRecord(
1657         original.metadata().bytes(),
1658         "exact compiled inputX",
1659         test_closure,
1660     );
1661     defer foreign.release();
1662     try std.testing.expectEqualSlices(u8, foreign.bytes(), published.metadata().bytes());
1663     try std.testing.expect(foreign != published.metadata());
1664     try std.testing.expect(!foreign.eql(published.metadata()));
1665     try std.testing.expectEqualStrings(test_manifest, published.metadata().compilerManifest());
1666     try std.testing.expectEqualStrings("exact compiled inputX", foreign.compilerManifest());
1667 }
1668 
1669 fn collidingDigest(_: []const u8) [32]u8 {
1670     return @splat(7);
1671 }
1672 
1673 test "revision store forced digest collisions never authorize unequal image reuse" {
1674     const owner = try Store.create(std.testing.allocator, test_limits);
1675     defer owner.release();
1676     storage(owner).digest_fn = collidingDigest;
1677     const kind = try owner.register(testContract());
1678     owner.freeze();
1679     const first = try testPublish(owner, kind, "value-a");
1680     defer first.release();
1681     const second = try testPublish(owner, kind, "value-b");
1682     defer second.release();
1683     try std.testing.expectEqual(first.view().digest, second.view().digest);
1684     try std.testing.expectEqual(first.view().bucket, second.view().bucket);
1685     try std.testing.expect(!first.eql(second));
1686     var request = testRequest(kind);
1687     request.expected_image = "value-b";
1688     const builder = try owner.begin(request, test_work);
1689     defer if (builder.abort(.rejected)) |failure| {
1690         var owned = failure;
1691         owned.deinit();
1692     };
1693     try std.testing.expectEqual(null, try builder.admitReuse(first));
1694     try std.testing.expectEqual(4, draft(builder).work.view().events.len);
1695 }
1696 
1697 test "revision store gate failure keeps the ancestor and installs no partial output" {
1698     const owner = try Store.create(std.testing.allocator, test_limits);
1699     defer owner.release();
1700     const kind = try owner.register(testContract());
1701     owner.freeze();
1702     const ancestor = try testPublish(owner, kind, "valid");
1703     defer ancestor.release();
1704     var request = testRequest(kind);
1705     request.parent = ancestor;
1706     const builder = try owner.begin(request, test_work);
1707     try builder.capture("invalid", &.{});
1708     try std.testing.expectError(error.UnencodableProduct, builder.seal(kind));
1709     var failure = builder.abort(.rejected).?;
1710     defer failure.deinit();
1711     try std.testing.expectEqual(.rejected, failure.work.outcome);
1712     try std.testing.expect(failure.work.charged.input_bytes > 0);
1713     try std.testing.expectEqual(1, owner.publicationCount());
1714     try std.testing.expectEqualStrings("valid", ancestor.view().exact.image);
1715 }
1716 
1717 test "revision store freezes exact schema and gate manifests before jobs" {
1718     const owner = try Store.create(std.testing.allocator, test_limits);
1719     defer owner.release();
1720     const kind = try owner.register(testContract());
1721     try std.testing.expectEqual(kind, try owner.register(testContract()));
1722     var changed = testContract();
1723     changed.schema.definition = "different semantics";
1724     try std.testing.expectError(error.KindContractMismatch, owner.register(changed));
1725     try std.testing.expectError(error.RegistrationOpen, owner.begin(testRequest(kind), test_work));
1726     owner.freeze();
1727     try std.testing.expectError(error.RegistrationFrozen, owner.register(testContract()));
1728 }
1729 
1730 fn allocationScenario(allocator: std.mem.Allocator) !void {
1731     const owner = try Store.create(allocator, test_limits);
1732     defer owner.release();
1733     const kind = try owner.register(testContract());
1734     owner.freeze();
1735     errdefer std.debug.assert(owner.publicationCount() == 0);
1736     const result = try testPublish(owner, kind, "valid");
1737     defer result.release();
1738     try std.testing.expectEqual(1, owner.publicationCount());
1739 }
1740 
1741 test "revision store retains exact cross store dependency closure and checks gate versions" {
1742     const allocator = std.testing.allocator;
1743     const first_owner = try Store.create(allocator, test_limits);
1744     const first_kind = try first_owner.register(testContract());
1745     first_owner.freeze();
1746     const ancestor = try testPublish(first_owner, first_kind, "valid");
1747     const second_owner = try Store.create(allocator, test_limits);
1748     defer second_owner.release();
1749     const second_kind = try second_owner.register(testContract());
1750     second_owner.freeze();
1751     const equal = try testPublish(second_owner, second_kind, "valid");
1752     defer equal.release();
1753     try std.testing.expect(ancestor.eql(equal));
1754     try std.testing.expect(ancestor.view().event.store_epoch != equal.view().event.store_epoch);
1755     var request = testRequest(second_kind);
1756     request.dependencies = &.{.{ .role = "input", .revision = ancestor }};
1757     const builder = try second_owner.begin(request, test_work);
1758     const stored = ancestor.view().semantic_record;
1759     ancestor.release();
1760     first_owner.release();
1761     const borrowed = draft(builder).dependencies[0].exact;
1762     try std.testing.expect(borrowed.ptr == stored.ptr);
1763     try std.testing.expectEqualSlices(u8, equal.view().semantic_record, borrowed);
1764     try builder.requireDependency("input", equal);
1765     try builder.capture("valid-successor", &.{});
1766     const successor = try builder.seal(second_kind);
1767     defer successor.release();
1768     const embedded = entry(successor).references[0];
1769     try std.testing.expect(embedded.ptr != equal.view().semantic_record.ptr);
1770     try successor.requireDependency("input", equal);
1771     try std.testing.expectError(
1772         error.UndeclaredProductInput,
1773         successor.requireDependency("source", equal),
1774     );
1775     try successor.requireGates(&.{.{ .name = "test-schema", .version = 1 }});
1776     try std.testing.expectError(error.MissingGateEvidence, successor.requireGates(&.{
1777         .{ .name = "test-schema", .version = 2 },
1778     }));
1779     try std.testing.expect(std.mem.indexOf(u8, successor.view().exact.inputs, "valid") != null);
1780 }
1781 
1782 test "revision store compares sealed dependencies through stored records" {
1783     const owner = try Store.create(std.testing.allocator, test_limits);
1784     defer owner.release();
1785     const kind = try owner.register(testContract());
1786     owner.freeze();
1787     const first = try testPublish(owner, kind, "value-a");
1788     defer first.release();
1789     const second = try testPublish(owner, kind, "value-b");
1790     defer second.release();
1791     const length = first.view().semantic_record.len;
1792     try std.testing.expectEqual(length, second.view().semantic_record.len);
1793     const successor = try testPublishSuccessor(owner, .{ .kind = kind, .source = first });
1794     defer successor.release();
1795     const reference = entry(successor).references[0];
1796     try std.testing.expect(reference.ptr == first.view().semantic_record.ptr);
1797     try std.testing.expectEqual(length, reference.len);
1798     try successor.requireDependency("input", first);
1799     try std.testing.expectError(
1800         error.UndeclaredProductInput,
1801         successor.requireDependency("input", second),
1802     );
1803     try std.testing.expectError(
1804         error.UndeclaredProductInput,
1805         successor.requireDependency("source", first),
1806     );
1807     try std.testing.expectError(
1808         error.UndeclaredProductInput,
1809         first.requireDependency("input", first),
1810     );
1811 }
1812 
1813 test "revision store reuse compares inputs as their encoded bytes" {
1814     const allocator = std.testing.allocator;
1815     var limits = test_limits;
1816     limits.revisions = 16;
1817     const owner = try Store.create(allocator, limits);
1818     defer owner.release();
1819     const kind = try owner.register(testContract());
1820     var tail_contract = testContract();
1821     tail_contract.identity.name = "tail-kind";
1822     const tail_kind = try owner.register(tail_contract);
1823     owner.freeze();
1824     const foreign_owner = try Store.create(allocator, test_limits);
1825     defer foreign_owner.release();
1826     const foreign_kind = try foreign_owner.register(testContract());
1827     foreign_owner.freeze();
1828     const first = try testPublish(owner, kind, "value-a");
1829     defer first.release();
1830     const second = try testPublish(owner, kind, "value-b");
1831     defer second.release();
1832     const foreign = try testPublish(foreign_owner, foreign_kind, "value-a");
1833     defer foreign.release();
1834     const successors = [_]TestSuccessor{
1835         .{ .kind = kind, .source = first },
1836         .{ .kind = kind, .source = second },
1837         .{ .kind = kind, .source = foreign },
1838         .{ .kind = kind, .source = first, .role = "inlet" },
1839         .{ .kind = kind, .source = first, .options = "default=collapse" },
1840         .{ .kind = tail_kind, .source = first },
1841     };
1842     var agreements: u32 = 0;
1843     for (successors) |prior_successor| {
1844         const prior = try testPublishSuccessor(owner, prior_successor);
1845         defer prior.release();
1846         for (successors) |request_successor| {
1847             const builder = try testBeginSuccessor(owner, request_successor);
1848             defer if (builder.abort(.rejected)) |failure| {
1849                 var owned = failure;
1850                 owned.deinit();
1851             };
1852             const prior_inputs = entry(prior).exact.inputs;
1853             const request_inputs = draft(builder).inputs;
1854             try std.testing.expectEqual(prior_inputs.len, request_inputs.len);
1855             const exact = std.mem.eql(u8, prior_inputs, request_inputs);
1856             try std.testing.expectEqual(prior_successor.eqlRequest(request_successor), exact);
1857             try std.testing.expectEqual(exact, draft(builder).eqlInputs(entry(prior)));
1858             agreements += 1;
1859         }
1860     }
1861     try std.testing.expectEqual(36, agreements);
1862 }
1863 
1864 test "revision store generation overflow and capacity failure never install output" {
1865     var limits = test_limits;
1866     limits.revisions = 1;
1867     const owner = try Store.create(std.testing.allocator, limits);
1868     defer owner.release();
1869     const kind = try owner.register(testContract());
1870     owner.freeze();
1871     storage(owner).event_counter = std.math.maxInt(u64);
1872     try std.testing.expectError(error.GenerationOverflow, testPublish(owner, kind, "valid"));
1873     try std.testing.expectEqual(0, owner.publicationCount());
1874     storage(owner).event_counter = 0;
1875     const published = try testPublish(owner, kind, "valid");
1876     defer published.release();
1877     try std.testing.expectError(error.StoreFull, testPublish(owner, kind, "valid-successor"));
1878     try std.testing.expectEqual(1, owner.publicationCount());
1879     try std.testing.expectEqual(1, published.view().event.counter);
1880 }
1881 
1882 test "revision store interns one copy of each compiler manifest and refuses more" {
1883     const owner = try Store.create(std.testing.allocator, test_limits);
1884     defer owner.release();
1885     const state = storage(owner);
1886     const first = try state.internManifest(test_manifest);
1887     var same: [test_manifest.len]u8 = undefined;
1888     @memcpy(&same, test_manifest);
1889     const repeated = try state.internManifest(&same);
1890     try std.testing.expect(first.ptr == repeated.ptr);
1891     try std.testing.expectEqual(@as(u32, 1), state.manifest_count);
1892     const second = try state.internManifest("other compiled inputs");
1893     try std.testing.expect(first.ptr != second.ptr);
1894     try std.testing.expectEqual(@as(u32, 2), state.manifest_count);
1895     try std.testing.expectError(error.CompilerManifestLimit, state.internManifest("a third"));
1896     try std.testing.expectError(error.MissingCompilerManifest, state.internManifest(""));
1897 }
1898 
1899 test "revision store identity separates equal bytes published under different compilers" {
1900     const allocator = std.testing.allocator;
1901     const first_owner = try Store.create(allocator, test_limits);
1902     defer first_owner.release();
1903     const second_owner = try Store.create(allocator, test_limits);
1904     defer second_owner.release();
1905     const first_kind = try first_owner.register(testContract());
1906     const second_kind = try second_owner.register(testContract());
1907     first_owner.freeze();
1908     second_owner.freeze();
1909     const original = try testPublish(first_owner, first_kind, "value");
1910     defer original.release();
1911     const sibling = try testPublish(first_owner, first_kind, "value");
1912     defer sibling.release();
1913     try std.testing.expect(original.eql(original));
1914     try std.testing.expect(original.eql(sibling));
1915 
1916     var changed = testRequest(second_kind);
1917     changed.inputs.compiler_manifest = "exact compiled inputX";
1918     const builder = try second_owner.begin(changed, test_work);
1919     try builder.capture("value", &.{});
1920     const foreign = try builder.seal(second_kind);
1921     defer foreign.release();
1922     const left = original.view().exact;
1923     const right = foreign.view().exact;
1924     try std.testing.expectEqualSlices(u8, left.address, right.address);
1925     try std.testing.expectEqualSlices(u8, left.inputs, right.inputs);
1926     try std.testing.expectEqualSlices(u8, left.image, right.image);
1927     try std.testing.expect(!original.eql(foreign));
1928     try std.testing.expectEqualStrings(test_manifest, original.view().compiler_manifest);
1929     try std.testing.expectEqualStrings("exact compiled inputX", foreign.view().compiler_manifest);
1930 }
1931 
1932 test "revision store changed compiler codec or gate manifests refuse reuse before producers" {
1933     const owner = try Store.create(std.testing.allocator, test_limits);
1934     defer owner.release();
1935     const first_kind = try owner.register(testContract());
1936     var changed = testContract();
1937     changed.identity.version = 2;
1938     changed.schema.identity.version = 2;
1939     const changed_kind = try owner.register(changed);
1940     owner.freeze();
1941     const original = try testPublish(owner, first_kind, "valid");
1942     defer original.release();
1943     var requests: [3]Request = @splat(testRequest(first_kind));
1944     requests[0].inputs.compiler_manifest = "different compiled inputs";
1945     requests[1].inputs.versions = &.{.{ .name = "codec", .version = 2 }};
1946     requests[2].kind = changed_kind;
1947     for (requests) |request| {
1948         const builder = try owner.begin(request, test_work);
1949         try std.testing.expectEqual(null, try builder.admitReuse(original));
1950         var failure = builder.abort(.rejected).?;
1951         defer failure.deinit();
1952         try std.testing.expectEqual(0, failure.work.executed.counters.pass_runs);
1953         try std.testing.expectEqual(4, failure.work.events.len);
1954     }
1955 }
1956 
1957 test "revision store cleans allocation failure at capture gate receipt and insertion" {
1958     try std.testing.checkAllAllocationFailures(std.testing.allocator, allocationScenario, .{});
1959 }
1960 
1961 fn dependencyAllocationScenario(allocator: std.mem.Allocator, foreign: bool) !void {
1962     const owner = try Store.create(allocator, test_limits);
1963     defer owner.release();
1964     const kind = try owner.register(testContract());
1965     owner.freeze();
1966     const source_owner = if (foreign) try Store.create(allocator, test_limits) else owner;
1967     defer if (foreign) source_owner.release();
1968     const source_kind = if (foreign) try source_owner.register(testContract()) else kind;
1969     if (foreign) source_owner.freeze();
1970     const source = try testPublish(source_owner, source_kind, "valid");
1971     defer source.release();
1972     const published = owner.publicationCount();
1973     errdefer std.debug.assert(owner.publicationCount() == published);
1974     const successor = try testPublishSuccessor(owner, .{ .kind = kind, .source = source });
1975     defer successor.release();
1976     try successor.requireDependency("input", source);
1977     try std.testing.expectEqual(published + 1, owner.publicationCount());
1978 }
1979 
1980 test "revision store cleans allocation failure while retaining dependency revisions" {
1981     for ([_]bool{ false, true }) |foreign| {
1982         try std.testing.checkAllAllocationFailures(
1983             std.testing.allocator,
1984             dependencyAllocationScenario,
1985             .{foreign},
1986         );
1987     }
1988 }
1989 
1990 const test_pipeline = [_]record.Version{.{ .name = "producer", .version = 1 }};
1991 
1992 fn runTestProducer(builder: *Builder) !void {
1993     const work = builder.accounting();
1994     const pass = try work.begin(.pass, .{
1995         .identity = test_pipeline[0],
1996         .work = .{ .structural_visits = 5, .rewrite_attempts = 3 },
1997         .workspace = 100,
1998     });
1999     errdefer work.finish(pass, .rejected, .{}) catch {};
2000     const analysis = try work.begin(.analysis, .{
2001         .identity = .{ .name = "analysis", .version = 1 },
2002         .work = .{ .structural_visits = 2, .analysis_computations = 1 },
2003         .workspace = 100,
2004     });
2005     try work.finish(analysis, .success, .{ .counters = .{ .analysis_misses = 1 } });
2006     try work.finish(pass, .success, .{ .counters = .{ .pass_runs = 1 } });
2007 }
2008 
2009 const WorkObservation = struct {
2010     outcome: receipt.Outcome,
2011     charged: receipt.WorkVector,
2012     executed: receipt.Executed,
2013 
2014     fn from(work: receipt.WorkReceiptV1) WorkObservation {
2015         return .{ .outcome = work.outcome, .charged = work.charged, .executed = work.executed };
2016     }
2017 };
2018 
2019 const TestCandidate = union(enum) { cold, warm: *const Revision, restored: []const u8 };
2020 
2021 fn workAttempt(budget: receipt.Limits, candidate: TestCandidate) !WorkObservation {
2022     const owner = try Store.create(std.testing.allocator, test_limits);
2023     defer owner.release();
2024     const kind = try owner.register(testContract());
2025     owner.freeze();
2026     var request = testRequest(kind);
2027     request.inputs.pipeline = &test_pipeline;
2028     const builder = try owner.begin(request, budget);
2029     if (candidate == .warm) {
2030         var reused = (builder.admitReuse(candidate.warm) catch |err| {
2031             return failedAttempt(builder, err);
2032         }) orelse return failedAttempt(builder, error.UnexpectedCacheMiss);
2033         defer reused.deinit();
2034         return WorkObservation.from(reused.work);
2035     }
2036     if (candidate == .restored) {
2037         try std.testing.expect(try builder.screenRestored(candidate.restored, test_manifest));
2038     }
2039     runTestProducer(builder) catch |err| return failedAttempt(builder, err);
2040     builder.capture("valid", &.{}) catch |err| return failedAttempt(builder, err);
2041     const output = builder.seal(kind) catch |err| return failedAttempt(builder, err);
2042     defer output.release();
2043     return WorkObservation.from(output.view().work);
2044 }
2045 
2046 fn failedAttempt(builder: *Builder, err: anyerror) !WorkObservation {
2047     var failure = builder.abort(.rejected) orelse return error.MissingFailureReceipt;
2048     defer failure.deinit();
2049     if (err != error.WorkExhausted) return err;
2050     return WorkObservation.from(failure.work);
2051 }
2052 
2053 fn baselineWorkRevision(owner: *Store, kind: *const Kind) !*const Revision {
2054     var request = testRequest(kind);
2055     request.inputs.pipeline = &test_pipeline;
2056     const builder = try owner.begin(request, test_work);
2057     errdefer if (builder.abort(.rejected)) |failure| {
2058         var owned = failure;
2059         owned.deinit();
2060     };
2061     try runTestProducer(builder);
2062     try builder.capture("valid", &.{});
2063     return builder.seal(kind);
2064 }
2065 
2066 test "revision store cold warm and restored share every budget boundary" {
2067     const owner = try Store.create(std.testing.allocator, test_limits);
2068     defer owner.release();
2069     const kind = try owner.register(testContract());
2070     owner.freeze();
2071     const baseline = try baselineWorkRevision(owner, kind);
2072     defer baseline.release();
2073     const charge = baseline.view().work.charged;
2074     inline for (@typeInfo(receipt.WorkVector).@"struct".field_names) |field| {
2075         for ([_]i64{ -1, 0, 1 }) |offset| {
2076             var budget = test_work;
2077             budget.allowance = charge;
2078             const value: i64 = @intCast(@field(charge, field));
2079             @field(budget.allowance, field) = @intCast(value + offset);
2080             const cold = try workAttempt(budget, .cold);
2081             const warm = try workAttempt(budget, .{ .warm = baseline });
2082             const restored = try workAttempt(budget, .{
2083                 .restored = baseline.view().semantic_record,
2084             });
2085             try std.testing.expectEqual(cold.outcome, warm.outcome);
2086             try std.testing.expectEqualDeep(cold.charged, warm.charged);
2087             try std.testing.expectEqual(cold.outcome, restored.outcome);
2088             try std.testing.expectEqualDeep(cold.charged, restored.charged);
2089             try std.testing.expectEqualDeep(cold.executed.counters, restored.executed.counters);
2090             const expected: receipt.Outcome = if (offset < 0) .exhausted else .success;
2091             try std.testing.expectEqual(expected, cold.outcome);
2092             try std.testing.expectEqual(0, warm.executed.counters.pass_runs);
2093         }
2094     }
2095 }
2096 
2097 test "revision store restored bytes bind cold comparison and never authorize replay" {
2098     const owner = try Store.create(std.testing.allocator, test_limits);
2099     defer owner.release();
2100     const kind = try owner.register(testContract());
2101     owner.freeze();
2102     const prior = try baselineWorkRevision(owner, kind);
2103     defer prior.release();
2104     var request = testRequest(kind);
2105     request.inputs.pipeline = &test_pipeline;
2106     const builder = try owner.begin(request, test_work);
2107     try std.testing.expect(!try builder.screenRestored(
2108         prior.view().semantic_record,
2109         "exact compiled inputX",
2110     ));
2111     try std.testing.expect(try builder.screenRestored(prior.view().semantic_record, test_manifest));
2112     try std.testing.expectError(
2113         error.RestoredCandidateRequiresExecution,
2114         builder.admitReuse(prior),
2115     );
2116     var refused = builder.abort(.rejected).?;
2117     defer refused.deinit();
2118     try std.testing.expectEqual(0, refused.work.executed.counters.pass_runs);
2119     const fresh = try owner.begin(request, test_work);
2120     try std.testing.expect(try fresh.screenRestored(prior.view().semantic_record, test_manifest));
2121     try runTestProducer(fresh);
2122     try std.testing.expectError(error.UnexpectedImage, fresh.capture("valid-but-changed", &.{}));
2123     var mismatch = fresh.abort(.rejected).?;
2124     defer mismatch.deinit();
2125     try std.testing.expectEqual(1, mismatch.work.executed.counters.pass_runs);
2126     try std.testing.expectEqual(1, owner.publicationCount());
2127 }
2128 
2129 test "revision store screens a bounded number of candidate bytes before cold work" {
2130     var limits = test_limits;
2131     limits.candidate_count = 1;
2132     const owner = try Store.create(std.testing.allocator, limits);
2133     defer owner.release();
2134     const kind = try owner.register(testContract());
2135     owner.freeze();
2136     const prior = try testPublish(owner, kind, "valid");
2137     defer prior.release();
2138     const builder = try owner.begin(testRequest(kind), test_work);
2139     try std.testing.expect(!try builder.screenRestored("corrupt", test_manifest));
2140     try std.testing.expectEqual(null, try builder.admitReuse(prior));
2141     try std.testing.expectEqual(7, builder.accounting().view().events[0].executed.work.input_bytes);
2142     try builder.capture("valid", &.{});
2143     const published = try builder.seal(kind);
2144     defer published.release();
2145     try std.testing.expect(prior.eql(published));
2146 }
2147 
2148 test "revision store warm trace preserves analysis occurrence parents and phase order" {
2149     const owner = try Store.create(std.testing.allocator, test_limits);
2150     defer owner.release();
2151     const kind = try owner.register(testContract());
2152     owner.freeze();
2153     const baseline = try baselineWorkRevision(owner, kind);
2154     defer baseline.release();
2155     var request = testRequest(kind);
2156     request.inputs.pipeline = &test_pipeline;
2157     const builder = try owner.begin(request, test_work);
2158     var reused = (try builder.admitReuse(baseline)).?;
2159     defer reused.deinit();
2160     const cold = baseline.view().work;
2161     try std.testing.expectEqual(cold.events.len, reused.work.events.len);
2162     try std.testing.expectEqual(cold.maximum_live_storage, reused.work.maximum_live_storage);
2163     for (cold.events, reused.work.events) |expected, actual| {
2164         try std.testing.expectEqual(expected.phase, actual.phase);
2165         try std.testing.expectEqual(expected.occurrence, actual.occurrence);
2166         try std.testing.expectEqual(expected.parent, actual.parent);
2167         try std.testing.expectEqual(expected.retained_storage, actual.retained_storage);
2168     }
2169 }
2170 
2171 test "revision store reserves the same physical output capacity before cold work and warm reuse" {
2172     var observed = std.testing.FailingAllocator.init(std.testing.allocator, .{});
2173     const owner = try Store.create(observed.allocator(), test_limits);
2174     defer owner.release();
2175     const kind = try owner.register(testContract());
2176     owner.freeze();
2177     const interned = try storage(owner).internManifest(test_manifest);
2178     try std.testing.expectEqual(test_manifest.len, interned.len);
2179     const before_cold = observed.allocated_bytes;
2180     const cold = try owner.begin(testRequest(kind), test_work);
2181     var cold_open = true;
2182     defer if (cold_open) {
2183         if (cold.abort(.rejected)) |failure| {
2184             var owned = failure;
2185             owned.deinit();
2186         }
2187     };
2188     const cold_bytes = observed.allocated_bytes - before_cold;
2189     try std.testing.expect(cold_bytes >= test_work.workspace + test_limits.record_bytes);
2190     try cold.capture("valid", &.{});
2191     const published = try cold.seal(kind);
2192     cold_open = false;
2193     defer published.release();
2194     try std.testing.expect(published.view().work.maximum_live_storage >=
2195         test_work.workspace + test_limits.record_bytes);
2196     const before_warm = observed.allocated_bytes;
2197     const warm = try owner.begin(testRequest(kind), test_work);
2198     var warm_open = true;
2199     defer if (warm_open) {
2200         if (warm.abort(.rejected)) |failure| {
2201             var owned = failure;
2202             owned.deinit();
2203         }
2204     };
2205     const warm_bytes = observed.allocated_bytes - before_warm;
2206     try std.testing.expect(warm_bytes >= test_work.workspace + test_limits.record_bytes);
2207     try std.testing.expectEqual(cold_bytes, warm_bytes);
2208     var reused = (try warm.admitReuse(published)) orelse return error.ExpectedWarmCandidate;
2209     warm_open = false;
2210     defer reused.deinit();
2211     try std.testing.expectEqualDeep(published.view().work.charged, reused.work.charged);
2212 }
2213 
2214 test "revision store reserves physical workspace before any cold producer or warm replay" {
2215     var observed = std.testing.FailingAllocator.init(std.testing.allocator, .{});
2216     const owner = try Store.create(observed.allocator(), test_limits);
2217     defer owner.release();
2218     const kind = try owner.register(testContract());
2219     owner.freeze();
2220     var prior: ?*const Revision = null;
2221     defer if (prior) |value| value.release();
2222     for ([_]bool{ false, true }) |warm| {
2223         const before = observed.allocated_bytes;
2224         const builder = try owner.begin(testRequest(kind), test_work);
2225         var open = true;
2226         defer if (open) {
2227             if (builder.abort(.rejected)) |failure| {
2228                 var owned = failure;
2229                 owned.deinit();
2230             }
2231         };
2232         const allocated = observed.allocated_bytes - before;
2233         try std.testing.expect(allocated >= test_work.workspace + test_limits.record_bytes);
2234         if (warm) {
2235             var reused = (try builder.admitReuse(prior.?)).?;
2236             open = false;
2237             reused.deinit();
2238         } else {
2239             try builder.capture("valid", &.{});
2240             const output = try builder.seal(kind);
2241             open = false;
2242             prior = output;
2243         }
2244     }
2245 }
2246 
2247 test "revision workspace leases remain separate and alive after builder and store release" {
2248     const owner = try Store.create(std.testing.allocator, test_limits);
2249     var owner_open = true;
2250     defer if (owner_open) owner.release();
2251     const kind = try owner.register(testContract());
2252     owner.freeze();
2253     const builder = try owner.begin(testRequest(kind), test_work);
2254     var open = true;
2255     defer if (open) {
2256         if (builder.abort(.rejected)) |failure| {
2257             var owned = failure;
2258             owned.deinit();
2259         }
2260     };
2261     const producer = try builder.acquireWorkspace(.producer);
2262     defer producer.release();
2263     @memset(producer.bytes(), 0x23);
2264     const scratch = try builder.acquireWorkspace(.scratch);
2265     @memset(scratch.bytes(), 0xb6);
2266     scratch.release();
2267     try std.testing.expectEqual(
2268         test_work.workspace - test_limits.gate_scratch_bytes,
2269         producer.bytes().len,
2270     );
2271     try std.testing.expectError(
2272         error.WorkspaceAlreadyLeased,
2273         builder.acquireWorkspace(.producer),
2274     );
2275     try builder.capture("valid", &.{});
2276     const published = try builder.seal(kind);
2277     open = false;
2278     published.release();
2279     owner.release();
2280     owner_open = false;
2281     for (producer.bytes()) |byte| try std.testing.expectEqual(0x23, byte);
2282     producer.bytes()[0] = 0x42;
2283     try std.testing.expectEqual(0x42, producer.bytes()[0]);
2284 }
2285 
2286 const WorkspaceReuseCase = struct {
2287     workspace: u64 = test_work.workspace,
2288     scratch: u32 = test_limits.gate_scratch_bytes,
2289     reuse: bool = false,
2290 };
2291 
2292 fn checkWorkspaceCandidate(candidate: *const Revision, request: WorkspaceReuseCase) !void {
2293     var limits = test_limits;
2294     limits.gate_scratch_bytes = request.scratch;
2295     const owner = try Store.create(std.testing.allocator, limits);
2296     defer owner.release();
2297     const kind = try owner.register(testContract());
2298     owner.freeze();
2299     var input = testRequest(kind);
2300     input.inputs.pipeline = &test_pipeline;
2301     var budget = test_work;
2302     budget.workspace = request.workspace;
2303     budget.allowance = receipt.WorkVector.uniform(8 * 1024 * 1024);
2304     const builder = try owner.begin(input, budget);
2305     var open = true;
2306     defer if (open) {
2307         var failure = builder.abort(.rejected).?;
2308         failure.deinit();
2309     };
2310     const charged = builder.accounting().view().charged;
2311     if (try builder.admitReuse(candidate)) |value| {
2312         open = false;
2313         var reused = value;
2314         defer reused.deinit();
2315         try std.testing.expect(request.reuse);
2316         try std.testing.expectEqual(@as(u64, 0), reused.work.executed.counters.pass_runs);
2317         try std.testing.expect(candidate.eql(reused.revision));
2318         return;
2319     }
2320     try std.testing.expect(!request.reuse);
2321     const before = builder.accounting().view();
2322     try std.testing.expectEqual(.running, before.outcome);
2323     try std.testing.expectEqualDeep(charged, before.charged);
2324     try std.testing.expectEqual(@as(usize, 4), before.events.len);
2325     try std.testing.expectEqual(@as(u64, 0), before.executed.counters.pass_runs);
2326     try std.testing.expectEqual(
2327         candidate.view().semantic_record.len,
2328         before.events[0].executed.work.input_bytes,
2329     );
2330     {
2331         const lease = try builder.acquireWorkspace(.producer);
2332         defer lease.release();
2333         try std.testing.expectEqual(request.workspace - request.scratch, lease.bytes().len);
2334     }
2335     try runTestProducer(builder);
2336     try builder.capture("valid", &.{});
2337     const result = try builder.seal(kind);
2338     open = false;
2339     defer result.release();
2340     try std.testing.expect(candidate.eql(result));
2341     try std.testing.expectEqual(@as(u64, 1), result.view().work.executed.counters.pass_runs);
2342 }
2343 
2344 test "revision store leaves reserved workspace bytes for producers to write" {
2345     const backing = try std.testing.allocator.alloc(u8, 4 * 1024 * 1024);
2346     defer std.testing.allocator.free(backing);
2347     @memset(backing, 0x5a);
2348     var fixed = std.heap.FixedBufferAllocator.init(backing);
2349     const owner = try Store.create(fixed.allocator(), test_limits);
2350     defer owner.release();
2351     const kind = try owner.register(testContract());
2352     owner.freeze();
2353     const builder = try owner.begin(testRequest(kind), test_work);
2354     defer {
2355         if (builder.abort(.rejected)) |failure| {
2356             var owned = failure;
2357             owned.deinit();
2358         }
2359     }
2360     const producer = try builder.acquireWorkspace(.producer);
2361     defer producer.release();
2362     const scratch = try builder.acquireWorkspace(.scratch);
2363     defer scratch.release();
2364     try std.testing.expect(producer.bytes().len > 0);
2365     try std.testing.expect(std.mem.allEqual(u8, producer.bytes(), 0x5a));
2366     try std.testing.expect(std.mem.allEqual(u8, scratch.bytes(), 0x5a));
2367 }
2368 
2369 test "revision store changed workspace regions miss before compiler work without refund" {
2370     const owner = try Store.create(std.testing.allocator, test_limits);
2371     defer owner.release();
2372     const kind = try owner.register(testContract());
2373     owner.freeze();
2374     const baseline = try baselineWorkRevision(owner, kind);
2375     defer baseline.release();
2376     const cases = [_]WorkspaceReuseCase{
2377         .{ .workspace = test_work.workspace - 1 },
2378         .{ .workspace = test_work.workspace + 1 },
2379         .{ .scratch = test_limits.gate_scratch_bytes - 1 },
2380         .{ .scratch = test_limits.gate_scratch_bytes + 1 },
2381         .{ .workspace = test_work.workspace + 1, .scratch = test_limits.gate_scratch_bytes + 1 },
2382         .{ .reuse = true },
2383     };
2384     for (cases) |request| try checkWorkspaceCandidate(baseline, request);
2385 }