milestone 19: hygiene sweep - dead ecs surface, single-source constants, tls classification, frontend state hazards, docker smoke network fix
CI / test (push) Successful in 1m46s
CI / test-aarch64 (push) Successful in 5m30s
CI / frontend (push) Successful in 46s
CI / cross (push) Successful in 8m12s
CI / docker (push) Successful in 3m46s

This commit is contained in:
2026-08-07 20:39:27 +02:00
parent 6f67940995
commit 6c507992e4
59 changed files with 1020 additions and 382 deletions
+2 -2
View File
@@ -268,8 +268,8 @@ pub const Db = struct {
/// `verifyImmutable` to compare against when it ends.
immutable_guard: ?ImmutableGuard = null,
/// Every mode carries `FULLMUTEX` (serialized mode). Phase 6's query logger
/// and Phase 8's API handlers share one handle across `std.Io` tasks, and a
/// Every mode carries `FULLMUTEX` (serialized mode). The query logger and
/// the web API handlers share one handle across `std.Io` tasks, and a
/// per-handle mutex inside SQLite is cheaper to be correct about than a
/// hand-rolled one; `config.db` write volume is negligible. `EXRESCODE`
/// makes `sqlite3_extended_errcode` meaningful from the first call.
+2 -1
View File
@@ -4,7 +4,8 @@
//!
//! The state is the gate other components read before a non-essential write:
//! the query logger holds its batches while `writesAllowed` is false, and
//! Phase 7 gates blocklist updates the same way. Nothing here edits a
//! the blocklist scheduler gates its refresh passes the same way
//! (`filter/manager.zig`'s `refreshGated`). Nothing here edits a
//! milestone-5 file; the gate is pulled, not pushed.
const std = @import("std");
+12 -7
View File
@@ -41,11 +41,14 @@ pub const hidden_marker = "hidden";
/// How long a batch waits before it re-reads the disk monitor.
pub const gate_retry_s = 1;
const max_domain_len = 253;
/// The widths of the query log's text columns, and the single source of them:
/// every producer that formats into one of these fields sizes its own buffer
/// from the constant here, so nothing can format wider than the row stores.
pub const max_domain_len = 253;
/// RFC 5952 text of any IPv6 address, zone identifier included.
const max_client_len = 45;
const max_reason_len = 32;
const max_upstream_len = 64;
pub const max_client_len = 45;
pub const max_reason_len = 32;
pub const max_upstream_len = 64;
/// One row on its way to `query_log`, carrying its own bytes.
pub const Entry = struct {
@@ -175,8 +178,9 @@ pub const Logger = struct {
/// that sees this must not expect rows.
writer_failed: std.atomic.Value(bool),
/// `queue_buf.len` is the backpressure cap — Phase 7 passes
/// `cfg.query_log_buffer_max` entries. The queue holds waiting tasks in
/// `queue_buf.len` is the backpressure cap — the composition root
/// (`app.zig:311`) allocates `cfg.logging.query_log_buffer_max` entries,
/// which `config/validate.zig` bounds. The queue holds waiting tasks in
/// intrusive lists, so a `Logger` must not be moved once anything has
/// touched it.
pub fn init(cfg: model.Logging, queue_buf: []Entry) Logger {
@@ -300,7 +304,8 @@ pub const Logger = struct {
/// it has flushed what was left.
///
/// A writer held by the disk gate keeps holding: it flushes when the disk
/// recovers, and Phase 7 cancels the task if it will not wait. A canceled
/// recovers, and the `group.cancel` that follows this call in `app.zig`
/// stops a writer that will not wait. A canceled
/// writer counts the batch it holds under `queries_dropped`.
pub fn shutdown(self: *Logger, io: std.Io) void {
self.queue.close(io);
+1 -1
View File
@@ -68,7 +68,7 @@ pub const RecreateReason = enum { missing, corrupt, not_a_database, quick_check_
pub const OpenResult = struct {
database: db.Db,
/// Non-null feeds a counter and the `/api/health` rollup in Phase 8.
/// Non-null feeds a counter and the `/api/health` rollup.
recreated: ?RecreateReason,
};
+2 -2
View File
@@ -9,8 +9,8 @@
//! a test helper — it deliberately does not answer that question.
//!
//! The import path is list / insert / deleteAll / count, plus the two runtime
//! calls `upsertSeen` and `pruneStale` that the Phase 7 client tracker owns.
//! Phase 8's REST surface is the third section: it speaks row ids and shows
//! calls `upsertSeen` and `pruneStale` that `server/clients.zig`'s tracker owns.
//! The REST surface is the third section: it speaks row ids and shows
//! every client, materialised ones included.
const std = @import("std");
+1 -1
View File
@@ -4,7 +4,7 @@
//! stable across an import, so an export carrying them would not re-import into
//! the same shape.
//!
//! The import path is list / insert / deleteAll / count. Phase 8's REST surface
//! The import path is list / insert / deleteAll / count. The REST surface
//! is the second half of this file: it speaks row ids, because that is what a
//! `/api/groups/{id}` request names.
+1 -1
View File
@@ -1,6 +1,6 @@
//! `local_records` and `forward_zones`.
//!
//! The import path is list / insert / deleteAll / count. Phase 8's REST surface
//! The import path is list / insert / deleteAll / count. The REST surface
//! follows each table's section: it speaks row ids, because that is what an
//! `/api/local-records/{id}` or `/api/forward-zones/{id}` request names.
+1 -1
View File
@@ -12,7 +12,7 @@
//! order as a whole is: `import` inserts the rules in export order, so the new
//! ids ascend in exactly the order this statement produced.
//!
//! The import path is list / insert / deleteAll / count. Phase 8's REST surface
//! The import path is list / insert / deleteAll / count. The REST surface
//! is the second half of this file: it speaks row ids, because that is what an
//! `/api/rules/{id}` request names.
+1 -1
View File
@@ -6,7 +6,7 @@
//! defaults so two exports taken minutes apart stay identical.
//!
//! The import path is list / insert / deleteAll / count; the runtime columns and
//! Phase 8's REST surface follow it, both keyed by row id.
//! the REST surface follow it, both keyed by row id.
const std = @import("std");
const Allocator = std.mem.Allocator;
+1 -1
View File
@@ -4,7 +4,7 @@
//! meaningful order — it matches what `Pool.init` expects — and `url` breaks
//! ties uniquely, which is what makes an export byte-stable.
//!
//! The import path is list / insert / deleteAll / count. Phase 8's REST surface
//! The import path is list / insert / deleteAll / count. The REST surface
//! is the second half of this file: it speaks row ids, because that is what an
//! `/api/upstreams/{id}` request names.
+6 -4
View File
@@ -4,7 +4,7 @@
//!
//! The pass touches `querylog.db` only. §3.6 walls `config.db` off from
//! retention churn, and the `hand_edited=0` client rows of §7.2 are pruned by
//! whatever creates them, which is Phase 7.
//! whatever creates them, which is the client tracker (`server/clients.zig`).
//!
//! Nothing here retries within a pass. A failed step logs at `warn` and the
//! next pass, a day later, does the same work again against the same data.
@@ -134,7 +134,8 @@ pub const Retention = struct {
_ = counter.fetchAdd(delta, .monotonic);
}
/// Daily loop, first pass immediately. Phase 7 starts it.
/// Daily loop, first pass immediately. The composition root starts it as a
/// concurrent task (`app.zig`).
///
/// `boot` rather than `awake`: a box that suspends overnight must still see
/// its day elapse.
@@ -148,8 +149,9 @@ pub const Retention = struct {
/// with the batch, and a checkpoint or a `VACUUM` can land inside a
/// transaction that is still open.
///
/// Retention takes `database` per call and opens nothing itself; Phase 7
/// opens the second connection. Isolation across the two connections is
/// Retention takes `database` per call and opens nothing itself; the
/// composition root opens the second connection with
/// `cli.DataDir.reopenQuerylogDb`. Isolation across the two connections is
/// SQLite's own — WAL plus the `busy_timeout` of `db.zig`'s open options —
/// so a pass that still loses a race sees `error.Busy` or `error.Locked`,
/// logs at `warn`, and repeats the work on the next interval.