9 Commits
Author SHA1 Message Date
mokhtar c5875af8c8 admin: live ring capacity is injectable, eviction test no longer timing-bound
Gates / test-aarch64 (push) Failing after 3h1m47s
Gates / package (push) Successful in 4m17s
Gates / container (push) Successful in 15s
CI / gates (push) Failing after 4h45m14s
Gates / frontend (push) Successful in 1m21s
Gates / test (push) Successful in 1m42s
2026-08-23 09:04:18 +02:00
mokhtar 409384ee9e build: bump version to 0.0.9
Gates / container (push) Successful in 15s
CI / gates (push) Failing after 6h11m8s
Gates / frontend (push) Successful in 1m26s
Gates / test (push) Successful in 1m45s
Gates / package (push) Successful in 34s
Gates / test-aarch64 (push) Failing after 3h6m37s
2026-08-22 23:32:47 +02:00
mokhtar 9eb78f6171 changelog: 0.0.9 releases today
Gates / frontend (push) Successful in 1m29s
Gates / test (push) Successful in 1m53s
Gates / test-aarch64 (push) Successful in 7m38s
Gates / package (push) Successful in 3m49s
Gates / container (push) Successful in 10s
CI / gates (push) Successful in 6h29m21s
2026-08-22 23:32:36 +02:00
mokhtar cc23c97218 milestone 33: contract closure — samples, file-authority enumeration, dead code, bundle ceiling
Gates / frontend (push) Successful in 1m34s
Gates / test (push) Successful in 2m3s
Gates / test-aarch64 (push) Failing after 3h13m33s
Gates / package (push) Successful in 5m20s
Gates / container (push) Successful in 15s
CI / gates (push) Failing after 6h30m45s
2026-08-22 23:31:37 +02:00
mokhtar 5da4652e89 querylog: return to the default checkpoint cadence 2026-08-22 23:10:17 +02:00
mokhtar 7e0df5fd94 milestone 32: task-shaped configuration, file mode as a rendering, config status api
Gates / frontend (push) Successful in 1m22s
Gates / test (push) Successful in 1m54s
Gates / test-aarch64 (push) Successful in 7m57s
Gates / package (push) Successful in 5m29s
Gates / container (push) Successful in 10s
CI / gates (push) Successful in 32m51s
2026-08-22 22:42:50 +02:00
mokhtar 025edbb093 milestone 31: concurrent upstream exchanges, dot session reuse, queue metrics
Gates / frontend (push) Successful in 1m26s
Gates / test (push) Successful in 1m55s
Gates / test-aarch64 (push) Failing after 3h1m8s
Gates / package (push) Successful in 3m55s
Gates / container (push) Successful in 15s
CI / gates (push) Failing after 3h21m29s
2026-08-22 19:54:02 +02:00
mokhtar 648d9b4496 milestone 30: overview as a dashboard, explicit health contract, period aggregations
Gates / frontend (push) Successful in 1m32s
Gates / test (push) Successful in 1m54s
Gates / package (push) Successful in 5m28s
Gates / container (push) Successful in 14s
Gates / test-aarch64 (push) Failing after 3h10m0s
CI / gates (push) Failing after 3h11m55s
2026-08-22 16:45:15 +02:00
mokhtarandClaude Fable 5 17422fac21 agents: move opus-coder to the global scope
The routing rule is global, so the agent it names lives next to it now
(~/.claude/agents/opus-coder.md), at medium effort and without the
milestone-spec wording that only fit this repository.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-22 10:53:19 +02:00
3 changed files with 2 additions and 95 deletions
-5
View File
@@ -101,11 +101,6 @@ jobs:
sudo apt-get update -qq sudo apt-get update -qq
sudo apt-get install -qq -y --no-install-recommends qemu-user sudo apt-get install -qq -y --no-install-recommends qemu-user
# qemu 11.1.0 has a TCG regression: its translation-block optimization
# takes the panic branch of Zig's UBSan pointer-overflow check on a
# valid in-bounds pointer (11.0.3 and earlier are clean; bisected via
# the Arch archive). This image's qemu 8.2 is not affected — do not
# upgrade the emulator past 11.0.x until qemu fixes it.
- name: Run test suite under qemu (plain suite, no -Dintegration) - name: Run test suite under qemu (plain suite, no -Dintegration)
run: zig build test-aarch64 -fqemu run: zig build test-aarch64 -fqemu
+2 -55
View File
@@ -1334,13 +1334,6 @@ test "shutdown writes the batch the writer holds and the rest of the queue" {
&database, &database,
@as(?*disk_monitor.Monitor, null), @as(?*disk_monitor.Monitor, null),
}); });
// Declared after the `database.close` defer so LIFO stops the writer first:
// an early return anywhere below would otherwise close the handle under a
// live writer and leave `Threaded.deinit` joining a task nothing ends.
defer {
logger.shutdown(io);
future.await(io) catch {};
}
var names: [250][32]u8 = undefined; var names: [250][32]u8 = undefined;
for (&names, 0..) |*name, i| { for (&names, 0..) |*name, i| {
@@ -1427,12 +1420,6 @@ test "the writer holds an entry for the length of the flush interval" {
&database, &database,
@as(?*disk_monitor.Monitor, null), @as(?*disk_monitor.Monitor, null),
}); });
// See the note in "shutdown writes the batch the writer holds": this must
// run before the deferred `database.close`.
defer {
logger.shutdown(io);
future.await(io) catch {};
}
logger.log(io, sampleEntry(1, "only.example")); logger.log(io, sampleEntry(1, "only.example"));
@@ -1479,12 +1466,6 @@ test "a full batch flushes without waiting for the interval" {
&database, &database,
@as(?*disk_monitor.Monitor, null), @as(?*disk_monitor.Monitor, null),
}); });
// See the note in "shutdown writes the batch the writer holds": this must
// run before the deferred `database.close`.
defer {
logger.shutdown(io);
future.await(io) catch {};
}
for (0..150) |i| logger.log(io, sampleEntry(@intCast(i), "burst.example")); for (0..150) |i| logger.log(io, sampleEntry(@intCast(i), "burst.example"));
@@ -1532,12 +1513,6 @@ test "a gated flush holds the batch until the disk recovers" {
@as([]const Entry, &entries), @as([]const Entry, &entries),
@as(?*disk_monitor.Monitor, &monitor), @as(?*disk_monitor.Monitor, &monitor),
}); });
// This task is `flush`, not `runWriter`: no queue shutdown can release it,
// so only cancellation ends it on an early return. Declared after the
// `writer.deinit`/`database.close` defers so LIFO runs it first.
defer {
_ = future.cancel(io) catch {};
}
const poll: std.Io.Clock.Duration = .{ .raw = .fromMilliseconds(5), .clock = .awake }; const poll: std.Io.Clock.Duration = .{ .raw = .fromMilliseconds(5), .clock = .awake };
var waited: usize = 0; var waited: usize = 0;
@@ -1659,12 +1634,6 @@ test "the gating episode opens on the gate, turns losing on a drop, and clears o
&database, &database,
@as(?*disk_monitor.Monitor, &monitor), @as(?*disk_monitor.Monitor, &monitor),
}); });
// See the note in "shutdown writes the batch the writer holds": this must
// run before the deferred `database.close`.
defer {
logger.shutdown(io);
future.await(io) catch {};
}
const poll: std.Io.Clock.Duration = .{ .raw = .fromMilliseconds(5), .clock = .awake }; const poll: std.Io.Clock.Duration = .{ .raw = .fromMilliseconds(5), .clock = .awake };
var waited: usize = 0; var waited: usize = 0;
@@ -1688,14 +1657,11 @@ test "the gating episode opens on the gate, turns losing on a drop, and clears o
// The disk recovers: the held batch goes out and the episode ends. // The disk recovers: the held batch goes out and the episode ends.
monitor.state_raw.store(@intFromEnum(disk_monitor.State.ok), .monotonic); monitor.state_raw.store(@intFromEnum(disk_monitor.State.ok), .monotonic);
waited = 0; waited = 0;
// The write is the completion condition, not the episode: `flush` reopens while (logger.gateEpisode() != .open) : (waited += 1) {
// the gate before it calls `writeBatch`, so a poll on the episode alone
// returns while the row is still in flight and `rows_written` is still 0.
while (logger.rows_written.load(.monotonic) == 0) : (waited += 1) {
try testing.expect(waited < 400); try testing.expect(waited < 400);
try poll.sleep(io); try poll.sleep(io);
} }
try testing.expectEqual(GateEpisode.open, logger.gateEpisode()); try testing.expect(logger.rows_written.load(.monotonic) > 0);
// The count keeps the history the state does not. // The count keeps the history the state does not.
try testing.expect(logger.queries_dropped.load(.monotonic) > 0); try testing.expect(logger.queries_dropped.load(.monotonic) > 0);
@@ -1770,13 +1736,6 @@ test "a gate that closes mid-enqueue still gets the discard that follows it" {
// The producer enters `enqueue` with the gate open — which is the reading a // The producer enters `enqueue` with the gate open — which is the reading a
// sample taken before the loop would keep for the rest of the call. // sample taken before the loop would keep for the rest of the call.
var producer = try io.concurrent(logOne, .{ &logger, io }); var producer = try io.concurrent(logOne, .{ &logger, io });
// The producer parks inside `enqueue` and only `release` frees it: an early
// return below would otherwise leave `Threaded.deinit` joining it forever.
defer {
discard_stall.armed = false;
discard_stall.release.set(io);
producer.await(io);
}
discard_stall.parked.waitUncancelable(io); discard_stall.parked.waitUncancelable(io);
// The producer is parked with the row it will evict still on the queue, so // The producer is parked with the row it will evict still on the queue, so
@@ -1840,12 +1799,6 @@ test "a canceled writer counts the batch it was holding" {
&database, &database,
@as(?*disk_monitor.Monitor, &monitor), @as(?*disk_monitor.Monitor, &monitor),
}); });
// Cancellation is this case's subject, so the guard is the same operation
// the body performs; declared after the `database.close` defer so LIFO ends
// the writer before the handle goes away.
defer {
_ = future.cancel(io) catch {};
}
const poll: std.Io.Clock.Duration = .{ .raw = .fromMilliseconds(5), .clock = .awake }; const poll: std.Io.Clock.Duration = .{ .raw = .fromMilliseconds(5), .clock = .awake };
var waited: usize = 0; var waited: usize = 0;
@@ -1889,12 +1842,6 @@ test "a disk-gated writer drops what it holds at shutdown instead of hanging" {
&database, &database,
@as(?*disk_monitor.Monitor, &monitor), @as(?*disk_monitor.Monitor, &monitor),
}); });
// See the note in "shutdown writes the batch the writer holds": this must
// run before the deferred `fx.deinit` and `database.close`.
defer {
logger.shutdown(io);
future.await(io) catch {};
}
const poll: std.Io.Clock.Duration = .{ .raw = .fromMilliseconds(5), .clock = .awake }; const poll: std.Io.Clock.Duration = .{ .raw = .fromMilliseconds(5), .clock = .awake };
var waited: usize = 0; var waited: usize = 0;
-35
View File
@@ -211,13 +211,6 @@ test "S8 case 1: the logger writes a real querylog.db end to end" {
log_db.database(), log_db.database(),
@as(?*disk_monitor.Monitor, null), @as(?*disk_monitor.Monitor, null),
}); });
// Declared after the `log_db.deinit` defer so LIFO stops the writer first:
// an early return below would otherwise close the database under a live
// writer and leave the never-closed queue parking it forever.
defer {
query_log.shutdown(io);
future.await(io) catch {};
}
var name_buf: [32]u8 = undefined; var name_buf: [32]u8 = undefined;
for (0..250) |i| { for (0..250) |i| {
@@ -259,13 +252,6 @@ test "S8 case 2: a single entry reaches the file once the flush interval passes"
log_db.database(), log_db.database(),
@as(?*disk_monitor.Monitor, null), @as(?*disk_monitor.Monitor, null),
}); });
// Declared after the `log_db.deinit` defer so LIFO stops the writer first:
// an early return below would otherwise close the database under a live
// writer and leave the never-closed queue parking it forever.
defer {
query_log.shutdown(io);
future.await(io) catch {};
}
query_log.log(io, entryAt(1, "only.example")); query_log.log(io, entryAt(1, "only.example"));
@@ -314,13 +300,6 @@ test "S8 case 3: a full queue drops the oldest entries and the newest survive" {
log_db.database(), log_db.database(),
@as(?*disk_monitor.Monitor, &monitor), @as(?*disk_monitor.Monitor, &monitor),
}); });
// Declared after the `log_db.deinit` defer so LIFO stops the writer first:
// an early return below would otherwise close the database under a live
// writer and leave the never-closed queue parking it forever.
defer {
query_log.shutdown(io);
future.await(io) catch {};
}
try awaitCount(&query_log.batches_gated, 1, 200); try awaitCount(&query_log.batches_gated, 1, 200);
try testing.expectEqual(@as(i64, 0), try queries_repo.countRows(log_db.database())); try testing.expectEqual(@as(i64, 0), try queries_repo.countRows(log_db.database()));
@@ -362,13 +341,6 @@ test "S8 case 4: the privacy transforms reach the stored rows" {
log_db.database(), log_db.database(),
@as(?*disk_monitor.Monitor, null), @as(?*disk_monitor.Monitor, null),
}); });
// Declared after the `log_db.deinit` defer so LIFO stops the writer first:
// an early return below would otherwise close the database under a live
// writer and leave the never-closed queue parking it forever.
defer {
query_log.shutdown(io);
future.await(io) catch {};
}
var name_buf: [32]u8 = undefined; var name_buf: [32]u8 = undefined;
for (0..20) |i| { for (0..20) |i| {
@@ -461,13 +433,6 @@ test "S8 case 6: a critical disk gates the flushes and recovery releases them" {
log_db.database(), log_db.database(),
@as(?*disk_monitor.Monitor, &monitor), @as(?*disk_monitor.Monitor, &monitor),
}); });
// Declared after the `log_db.deinit` defer so LIFO stops the writer first:
// an early return below would otherwise close the database under a live
// writer and leave the never-closed queue parking it forever.
defer {
query_log.shutdown(io);
future.await(io) catch {};
}
try awaitCount(&query_log.batches_gated, 1, 200); try awaitCount(&query_log.batches_gated, 1, 200);
try testing.expectEqual(@as(u64, 0), query_log.rows_written.load(.monotonic)); try testing.expectEqual(@as(u64, 0), query_log.rows_written.load(.monotonic));