cut: schema gate — refuse to release an undisclosed querylog schema change

the gate recomputes the previous release tag's ddl fingerprint from the
remote peeled object and compares it against the tree's; a change must
be disclosed by 'resets your query history' in the version's changelog
section. the 0.0.9 reset shipped with an announcement claiming no
schema change; this makes the impact mechanical instead of remembered.
This commit is contained in:
2026-08-23 15:07:27 +02:00
parent a8fd9fee48
commit fe71efe335
5 changed files with 461 additions and 18 deletions
+13 -1
View File
@@ -80,6 +80,14 @@ pub const ddl: [:0]const u8 =
\\VALUES (1, unixepoch(), unixepoch() + 1);
;
/// The fingerprint of an arbitrary DDL text. `tools/cut.zig` calls this at
/// runtime on the DDL of the previous release tag, so the release gate and the
/// server compute the same number from the same function rather than from two
/// copies of one expression.
pub fn fingerprintOf(text: []const u8) i32 {
return @bitCast(std.hash.Crc32.hash(text));
}
/// `PRAGMA user_version` is a signed 32-bit field. Deriving the fingerprint from
/// the DDL means editing the schema automatically invalidates every existing
/// file — which is exactly the policy.
@@ -87,7 +95,7 @@ pub const fingerprint: i32 = blk: {
// Covers the CRC lookup-table generation in std.hash.crc, which evaluates
// under this scope's quota and overflows the 1000 default (and 100k).
@setEvalBranchQuota(2_000_000);
break :blk @bitCast(std.hash.Crc32.hash(ddl));
break :blk fingerprintOf(ddl);
};
const set_user_version = std.fmt.comptimePrint("PRAGMA user_version = {d};", .{fingerprint});
@@ -280,6 +288,10 @@ const testing = std.testing;
test "fingerprint matches a fresh hash of the DDL" {
try testing.expectEqual(fingerprint, @as(i32, @bitCast(std.hash.Crc32.hash(ddl))));
// The runtime entry point the release gate uses is the same function the
// comptime constant is built from.
try testing.expectEqual(fingerprint, fingerprintOf(ddl));
try testing.expect(fingerprintOf(ddl[0 .. ddl.len - 1]) != fingerprint);
}
test "ddl creates the query-log tables and every index" {