-
v0.0.21
StableGates / frontend (push) Successful in 2m1sGates / test (push) Successful in 2m25sGates / test-aarch64 (push) Successful in 8m19sGates / package (push) Successful in 4m22sGates / container (push) Successful in 12sCI / gates (push) Successful in 28m50sRelease / guard (push) Successful in 35sGates / frontend (push) Successful in 1m57sGates / test (push) Successful in 2m24sGates / test-aarch64 (push) Successful in 7m38sGates / package (push) Successful in 54sGates / container (push) Successful in 18sRelease / gates (push) Successful in 11m18sRelease / publish (push) Successful in 4m56sreleased this
2026-09-12 19:12:55 +00:00 | 0 commits to master since this releaseChanged
- An upstream warning means the pool stopped trusting the endpoint. A Diagnostics episode opens when an upstream reaches the health failure threshold and closes on the success that clears it, instead of one card per lost exchange. Failures during backoff raise the card's occurrence count. The episode detail and the
nxdns checkreport name the concrete cause behind the classification,SendFailed (cause BrokenPipe).
Artifacts
26615c4b52cbc1e60468bc40849be025b4214caa5a2b7dcde0a86da7cab3b4ce nxdns-0.0.21-x86_64-linux-musl.tar.gz 29746c9a68b7c07c1f89be216b6ba59a750f7d67767781482b100558567f19af nxdns-0.0.21-aarch64-linux-musl.tar.gz d7f0f99e80b7cdd1c621235a2ccb8f1ab9537e25728a69beb9da63e2b97e2f32 IMAGE-DIGEST.txtgit.mial.net/mokhtar/nxdns:0.0.21@sha256:ce1fef32c7ee6c23656abd94e53e4d4d6b1d34fe88a2c842b82c7202d8b904c3Commits since v0.0.20
f2dd6ad build: bump version to 0.0.21 08cdf86 upstream: a diagnostics episode follows health, and a peer fault carries its causeDownloads
- An upstream warning means the pool stopped trusting the endpoint. A Diagnostics episode opens when an upstream reaches the health failure threshold and closes on the success that clears it, instead of one card per lost exchange. Failures during backoff raise the card's occurrence count. The episode detail and the
-
v0.0.20
StableGates / frontend (push) Successful in 1m52sGates / test (push) Successful in 2m22sGates / test-aarch64 (push) Successful in 8m10sGates / package (push) Successful in 4m22sGates / container (push) Successful in 10sCI / gates (push) Successful in 28m22sRelease / guard (push) Successful in 35sGates / frontend (push) Successful in 1m53sGates / test (push) Successful in 2m20sGates / test-aarch64 (push) Successful in 7m26sGates / package (push) Successful in 51sGates / container (push) Successful in 11sRelease / gates (push) Successful in 10m52sRelease / publish (push) Successful in 4m56sreleased this
2026-09-12 13:55:06 +00:00 | 2 commits to master since this releaseFixed
- A blocklist source no longer fails on a stale pooled connection. The fetcher reused a keep-alive connection from an earlier pass that the server had closed, and the standard client never retries one; every later download from that host failed with
HttpConnectionClosingat 0 ms. Downloads now sendconnection: closeand never enter the pool.
Artifacts
ae74e98e8ec9f6e63ea48371278660c1ba94ec4da8ecdd20afdcfb551850899d nxdns-0.0.20-x86_64-linux-musl.tar.gz da9f3a148983822e120c3ce657ac34aa4ae4a7d76d0d1ca2fd930e67c580126e nxdns-0.0.20-aarch64-linux-musl.tar.gz 80ded73a588da1dc90cd38c6202f13fb3fd7bcd73b9cd1f9cf545601dc9bdd3d IMAGE-DIGEST.txtgit.mial.net/mokhtar/nxdns:0.0.20@sha256:955379672493f64b59ed3f18899fb0808197492e2abd0eedcaa6c6ec6d1f3258Commits since v0.0.19
6e9a369 build: bump version to 0.0.20 f6fa43a filter: blocklist downloads never reuse a pooled connection, the peer closes it between passesDownloads
- A blocklist source no longer fails on a stale pooled connection. The fetcher reused a keep-alive connection from an earlier pass that the server had closed, and the standard client never retries one; every later download from that host failed with
-
v0.0.19
StableGates / frontend (push) Successful in 2m3sGates / test (push) Successful in 2m33sGates / test-aarch64 (push) Successful in 8m14sGates / package (push) Successful in 52sGates / container (push) Successful in 14sCI / gates (push) Successful in 12m0sRelease / guard (push) Successful in 33sGates / frontend (push) Successful in 2m36sGates / test (push) Successful in 3m47sGates / test-aarch64 (push) Successful in 7m24sGates / package (push) Successful in 50sGates / container (push) Successful in 15sRelease / gates (push) Successful in 12m19sRelease / publish (push) Successful in 6m37sreleased this
2026-09-12 09:14:36 +00:00 | 4 commits to master since this releaseChanged
- A failed blocklist download says why. The warning line and the Diagnostics event detail now carry the phase that failed, the concrete cause behind the classification (a reset connection, a truncated chunk, a TLS handshake fault), the HTTP status if a head arrived, the bytes received, and the elapsed time. The separate
http statuswarning is folded into that line. Same one line per failed source per pass as before.
Artifacts
4af595f259b225671e54186e00eb6574c6f0180f212f1fe9b8955d6b6b74b028 nxdns-0.0.19-x86_64-linux-musl.tar.gz b0d223b272794cf469484ff00edc1bd23ee5632c8c5c23ccc1cec802fe6ccb7b nxdns-0.0.19-aarch64-linux-musl.tar.gz b1afe29eed90b2e87e7fd603ea8e6e6478d96946861151efbd3275adf0ff4fe3 IMAGE-DIGEST.txtgit.mial.net/mokhtar/nxdns:0.0.19@sha256:b80023379b012db3898d78f716a5e6c6967459416252f528cc207cffae44b0e5Commits since v0.0.18
f4562ca filter: skip the read-only directory test as root, ci's runner ignores mode bits 250bdca build: bump version to 0.0.19 63f4f96 changelog: date the 0.0.19 section 5215819 filter: a failed blocklist download names its phase, cause, status, bytes and elapsed time bf79a22 docs: renovate's nix manager does not bump a tag ref; the regex manager recipe that doesDownloads
- A failed blocklist download says why. The warning line and the Diagnostics event detail now carry the phase that failed, the concrete cause behind the classification (a reset connection, a truncated chunk, a TLS handshake fault), the HTTP status if a head arrived, the bytes received, and the elapsed time. The separate
-
v0.0.18
StableGates / frontend (push) Successful in 2m34sGates / test (push) Successful in 2m39sGates / test-aarch64 (push) Successful in 8m16sGates / package (push) Successful in 4m21sGates / container (push) Successful in 16sCI / gates (push) Successful in 15m39sRelease / guard (push) Successful in 35sGates / frontend (push) Successful in 2m1sGates / test (push) Successful in 2m28sGates / test-aarch64 (push) Successful in 7m24sGates / package (push) Successful in 52sGates / container (push) Successful in 11sRelease / gates (push) Successful in 10m59sRelease / publish (push) Successful in 5m11sreleased this
2026-09-09 17:57:40 +00:00 | 9 commits to master since this releaseFixed
- The Overview scope pickers no longer sit apart, and a long device name no longer pushes the period picker off a phone screen. The Device and Period dropdowns fill their wrappers and stand side by side; a long name truncates with an ellipsis in the trigger and stays fully readable in the list.
Artifacts
b815a397c16f3f85603e2b0983274d6b3c8fbb8d238d06bbfa2eb8f8cfc1e740 nxdns-0.0.18-x86_64-linux-musl.tar.gz ed39ae26be9392045d3e462f36210e1557e4ce4a7e7638d64a697ebc051e7bbf nxdns-0.0.18-aarch64-linux-musl.tar.gz 26775f1fd8642a6b90ef34016559a917dc459f9cb980d4f2f83e87aeefa802f2 IMAGE-DIGEST.txtgit.mial.net/mokhtar/nxdns:0.0.18@sha256:2af3899f65c886120267806310c63e319c8bb891d1ab8b72145c43e3a6f5b488Commits since v0.0.17
bcd9bce build: bump version to 0.0.18 2b790c4 changelog: 0.0.18 section 1860ff5 admin: the overview pickers fill their wrappers and share a narrow rowDownloads
-
v0.0.17
StableGates / frontend (push) Successful in 2m23sGates / test (push) Successful in 3m15sGates / test-aarch64 (push) Successful in 8m38sGates / package (push) Successful in 5m0sGates / container (push) Successful in 19sCI / gates (push) Successful in 17m17sRelease / guard (push) Successful in 37sGates / frontend (push) Successful in 2m15sGates / test (push) Successful in 2m34sGates / test-aarch64 (push) Successful in 7m33sGates / package (push) Successful in 51sGates / container (push) Successful in 10sRelease / gates (push) Successful in 11m14sRelease / publish (push) Successful in 8m35sreleased this
2026-09-08 22:35:07 +00:00 | 12 commits to master since this releaseAdded
- A Nix flake with tag-pinned hashes.
flake.nixat the repository root buildsnxdnsforaarch64-linuxandx86_64-linuxfrom the release tarballs, and carries their hashes in a generated block. A consumer pins the flake to a release tag and gets the exact bytes that tag published;docs/how-to/install-with-nix.mdcovers the input, thenixpkgsfollows line, and Renovate.
Changed
- The release archive is written by the project's own tool.
zig build distno longer shells out to the runner'starandgzip; it writes the tar stream and the gzip container itself, with sorted entries, fixed modes, and zero timestamps. The tarball bytes now depend on the source tree, the compiler, and the admin bundle, and on nothing the host supplies — which is what lets a hash be pinned before CI rebuilds it. - The cut pins the release hashes before it commits.
zig build cutasserts the local Node, npm, and Zig match the versions CI pins, builds the release from the bumped manifest in a normalized environment, writes the resulting hashes intoflake.nix, and commits that file alongsidebuild.zig.zonas one commit. CI reverifies the pins on the bump commit and again on the tag, before anything is uploaded. nxdns versionno longer reports a git commit. The commit is gone from the command's output, fromGET /api/version, and from the admin footer, which now showsnxdns v<version>. A release identifies itself by version, and the bytes are reproducible from the tag, so a commit embedded in the binary told a reader nothing the tag did not.
Artifacts
8ee0b1f30b1ee43bcb0a0c8e789469fac794523e31468b54c199d0b571c8ab6b nxdns-0.0.17-x86_64-linux-musl.tar.gz b439ca554968b31e8d2b9a8ba9400fbc89dc27e0bb259d5d3526bc4221333c77 nxdns-0.0.17-aarch64-linux-musl.tar.gz 35ac38080eaf72f39fa6a97bd18bcfa3cc62df44b3228e52d35dc49682a24c52 IMAGE-DIGEST.txtgit.mial.net/mokhtar/nxdns:0.0.17@sha256:dde9833df05ce227a13618f3469cccd1be2ad0fcaf03f526c076a89bf7ce5c55Commits since v0.0.16
f168247 cut: build the release with the official zig tarball, skip hidden bundle files; re-pin 0.0.17 d596fd7 build: bump version to 0.0.17 f067742 cut: the pin stage compiles, and `zig build test` builds the cut binary a4eb749 changelog: 0.0.17 22abcd9 release: nix flake with tag-pinned hashes, reproducible tarballs (milestone 40) 3e57f43 cut: rerun a flaky release run once, resume after the tag 299d7af upstream: overlap attribution test builds its schedule with gatesDownloads
- A Nix flake with tag-pinned hashes.
-
v0.0.16
StableGates / frontend (push) Successful in 1m57sGates / test (push) Successful in 2m34sGates / test-aarch64 (push) Successful in 8m9sGates / package (push) Successful in 7m14sGates / container (push) Successful in 17sCI / gates (push) Successful in 18m17sRelease / guard (push) Successful in 33sGates / test-aarch64 (push) Successful in 7m22sGates / container (push) Successful in 11sRelease / gates (push) Successful in 10m35sGates / frontend (push) Successful in 2m8sGates / test (push) Successful in 2m16sGates / package (push) Successful in 44sRelease / publish (push) Successful in 10m4sreleased this
2026-09-07 22:05:41 +00:00 | 19 commits to master since this releaseThe Overview page is redesigned around the two dashboards people already know — Pi-hole's layout, NextDNS's charts — and every number in the admin is spelled one way.
Changed
- Overview reads like an analytics dashboard. Four centred totals (queries, blocked, active clients, and the blocked share), a smooth area chart of total and blocked queries where hovering marks the point and shows its figures beside it, a stacked client-activity chart in eight distinct hues with everything else as one gray band, and a row of cards under them: the cache hit rate as a progress bar, the query types as a single-hue ring, and the upstream breakdown.
- Overview can be scoped to one device. A device selector sits beside the period selector; both are URL state, so
/overview?period=7d&client=192.0.2.30is a link to exactly that view. The API takes the sameclientparameter onGET /api/overview, and the tile links carry the scope into Activity. - One formatting contract. Counts are thousands-grouped, percentages always show two decimals (15.44%, never 15.4%), rates one decimal, and durations their two largest nonzero units ("6d 4h", "12m 5s", "6d 5s"). A test sweeps the sources for any number formatted outside the one module.
- A quieter, more consistent chrome. One 4px corner radius everywhere, cards with a prominent title and a one-line description, the sidebar grouped into Monitoring and System with a status block at its foot (protection, queries per minute on Overview, uptime), and a top bar in place of the sidebar on narrow screens. The active navigation item and the accent blue are darkened to clear WCAG AA on their washes.
Artifacts
c682f6801aace3e1529b9a5e181abfc24fa3f421395bcc03aee19f9bcc6c908e nxdns-0.0.16-x86_64-linux-musl.tar.gz 0bfff7496e26bd10cd175a7e1e93e2ce94c1a2c3efa23348776b6258f44abb7f nxdns-0.0.16-aarch64-linux-musl.tar.gz 5ed07ca8e33c299669788e238e260c7f2a3db659f59e23f48c1ecf2331fb7569 IMAGE-DIGEST.txtgit.mial.net/mokhtar/nxdns:0.0.16@sha256:e5b7360d4cc6d6f32e77094c554103978ce875893613d84aad25935a9e940966Commits since v0.0.15
85b8be5 admin: overview redesign, device scope, one formatting contract (milestone 39) e656670 admin: ui polish pass, thirty findings from the emil auditDownloads
-
v0.0.15
StableGates / frontend (push) Successful in 1m51sGates / test (push) Successful in 2m29sGates / test-aarch64 (push) Successful in 7m24sRelease / guard (push) Successful in 32sGates / frontend (push) Successful in 2m14sGates / package (push) Successful in 4m56sGates / test (push) Successful in 2m20sGates / test-aarch64 (push) Successful in 7m25sGates / package (push) Successful in 1m3sGates / container (push) Successful in 15sCI / gates (push) Successful in 26m26sGates / container (push) Successful in 11sRelease / gates (push) Successful in 16m6sRelease / publish (push) Successful in 6m43sreleased this
2026-08-31 17:24:54 +00:00 | 21 commits to master since this releaseThe Activity page's history filters become a toolbar you can actually use. Filters apply as you set them, the client field stops asking you to remember IP addresses, and the whole admin picks up one coherent icon set.
Changed
- History filters apply live from a toolbar. The form-and-Apply-button row is gone. Domain text filters as you type (debounced), result and time are one-click controls, and a custom date range applies as one change. Every filter state is a bookmarkable URL.
- The client filter is a picker, not a text field. It lists the clients the server knows — named, sorted, multi-select — instead of asking for an exact address. Selected clients show as removable chips (first three, then a count), and a query can filter on up to 32 clients at once; the API accepts the same list.
- One icon set. Interface glyphs (dropdown carets, checkbox ticks, the search magnifier, status marks, back arrows) are now Phosphor icons instead of a mix of text characters and hand-drawn shapes.
- The admin bundle budget rises from 800,000 to 900,000 bytes. The client picker, the accessible menu and dialog primitives behind it, and the Phosphor icon components are the arrivals that spend it; the built assets sit at about 840,000 bytes.
Added
- Accessibility pass over the admin. Focus-visible rings on every control, labels wired to their inputs, keyboard-reachable menus and dialogs, and visible text where information previously lived only in hover titles.
Artifacts
c0f12429cc4755e8690388ef43d76b28a5a088e4737a294ae89e60a6932a034d nxdns-0.0.15-x86_64-linux-musl.tar.gz 739857763e84eb849bbbf4594a6f87f46e1834a4e9870d19f20cdf12fe7901d2 nxdns-0.0.15-aarch64-linux-musl.tar.gz 71f2261dbc3f073948370683b93768fc92fb1367c6610d86f5f0327a3b052c32 IMAGE-DIGEST.txtgit.mial.net/mokhtar/nxdns:0.0.15@sha256:b9053a0660b70639572e11697e75b21a3cc47e1fae09d1eeb92e8466ef0c58a3Commits since v0.0.14
2ae0c97 admin: per-icon phosphor imports, the barrel loads every icon module under vitest 2525b01 admin: phosphor icons replace hand-drawn svgs and text-character glyphs b774b05 activity: select-only multi-client filter d79dd0b admin: prettier formatting for the toolbar-era files, missed before ci ever ran them 039eeed admin: activity history filters become a live-apply toolbar c65d92d admin: title-only information becomes visible text 207252a admin: enable toggles become rac switches f1de804 admin: group sources and safe search become rac checkboxes 3c67496 admin: the mobile drawer becomes a rac disclosure, asset budget raised to 850,000 bytes 59d6be9 admin: associate inline field errors with their inputs 317d5dd admin: live query detail becomes a modal, live/history and period pickers become tabs and radios, client delete confirms in a dialog 79578e1 admin: reclaim the desktop header, move pause and log out to the sidebar d5613ee admin: pointer cursor on every buttonDownloads
-
v0.0.14
StableRelease / guard (push) Successful in 34sGates / frontend (push) Successful in 1m47sGates / test (push) Successful in 2m43sGates / test-aarch64 (push) Successful in 7m29sGates / package (push) Successful in 58sGates / container (push) Successful in 14sRelease / gates (push) Successful in 11m27sRelease / publish (push) Successful in 1m30sreleased this
2026-08-30 10:34:06 +00:00 | 34 commits to master since this releaseSchema changes stop costing you your query history. querylog.db is now version-stamped and migrated in place; the server refuses to start rather than ever reset a healthy file, and the release tooling refuses to ship a schema change that is neither migratable nor explicitly disclosed with recovery steps. Three releases (0.0.6, 0.0.9, 0.0.12) each discarded the log on upgrade; this ends that.
Changed
- querylog.db is migrated in place. The file now carries a schema version, and a release that changes the schema ships a migration that runs at startup: one consistent backup (
querylog.db.pre-migrate-<timestamp>, mode 0600, only the most recent kept), then every step and the version stamp in a single transaction. A failure before the commit rolls back and leaves your file exactly as it was. - The server refuses instead of resetting. A querylog.db it cannot use — newer than the binary, older than 0.0.12, or mid-migration failure — is left untouched and the server exits with a clear message instead of setting the file aside and starting an empty log. The exit code (2) tells systemd not to restart-loop a deliberate refusal. Corruption is the only case that still sets a file aside automatically.
- The release gate now enforces the contract. A schema change cannot be tagged unless it either ships a working migration (proven in CI against a frozen fixture of the previous schema, with shipped migration files locked byte-for-byte once released) or explicitly declares a break — which requires a version bump the server refuses on, a reset disclosure, and step-by-step restore instructions in this file.
One hazard to know when downgrading. The first start under this release restamps querylog.db from the old fingerprint to version 1 (contents untouched). If you later downgrade to 0.0.13 or older, that binary treats the new stamp as a schema mismatch, moves your file aside as
querylog.db.schema-changed-<timestamp>, and starts an empty log. To recover: return to 0.0.14 or newer, stop the server, move the emptyquerylog.dbaway and delete itsquerylog.db-walandquerylog.db-shmfiles (leaving them would corrupt the restored file), rename the.schema-changed-<timestamp>file back toquerylog.db, and start.Artifacts
bd75dbc880109880f5d9e1ef56862637d771f3dda29fca396371612c48d3e869 nxdns-0.0.14-x86_64-linux-musl.tar.gz 71e9102d536b6e87c8de892b538521c08e6ad26baf2e7a602755636243edac40 nxdns-0.0.14-aarch64-linux-musl.tar.gz 776d7b8392db091e0de3f24e17fff89bbd086588ecb2623b4893f2a10ef642f8 IMAGE-DIGEST.txtgit.mial.net/mokhtar/nxdns:0.0.14@sha256:c729fb4aa37054c5dbafa3a0d668898222e1c1e0364eeb955ef861a04707ebe9Commits since v0.0.8
09932b2 build: bump version to 0.0.14 272655f storage: version querylog.db and migrate it in place, never reset a healthy file dd5a9f6 build: bump version to 0.0.13 72cdbbd upstream: one absolute per-query budget across queueing and failover 6170571 build: bump version to 0.0.12 c847072 overview: one endpoint, live projections and a response cache (m36) 7cdb74e build: bump version to 0.0.11 4367003 changelog: 0.0.11 728b8d6 admin: draw the overview charts with visx 091962a build: bump version to 0.0.10 4fcbd0a changelog: 0.0.10 d961b15 db-mode config changes apply live in-process 17e6e93 admin: only the content region scrolls on wide screens 8a44d90 cut: schema gate — refuse to release an undisclosed querylog schema change 03149b5 ci: drop the one-insn-per-tb workaround, the qemu panic is an 11.1.0-only regression a972c8d logger tests: join every writer future before its database closes, fix the gate-open race 78d688a ci: run the aarch64 suite with one qemu insn per tb, tcg optimization falsely trips the ubsan pointer check fe5bd96 admin: live ring capacity is injectable, eviction test no longer timing-bound 1f215ac build: bump version to 0.0.9 2f86cd7 changelog: 0.0.9 releases today 51cda8b milestone 33: contract closure — samples, file-authority enumeration, dead code, bundle ceiling e5f23d5 querylog: return to the default checkpoint cadence 24521ab milestone 32: task-shaped configuration, file mode as a rendering, config status api c99a37d milestone 31: concurrent upstream exchanges, dot session reuse, queue metrics 623667e milestone 30: overview as a dashboard, explicit health contract, period aggregations 0e83477 agents: move opus-coder to the global scope fa323c7 milestone 29: activity — history, live and policy simulation on one surface 0fd6bbd milestone 28: query provenance — every logged query is exactly explainable 7e6cb50 release cut: bump-kind justfile recipe and a compiled, tested cut tool 8a17e9e admin: fix dashboard phantom scroll, drop last-failure column from upstream table 0107df5 spec: measurement window is the deployment side's callDownloads
- querylog.db is migrated in place. The file now carries a schema version, and a release that changes the schema ships a migration that runs at startup: one consistent backup (
-
v0.0.13
StableRelease / guard (push) Successful in 34sGates / frontend (push) Successful in 1m39sGates / test (push) Successful in 2m27sGates / test-aarch64 (push) Successful in 8m9sGates / package (push) Successful in 4m24sGates / container (push) Successful in 16sRelease / gates (push) Successful in 15m18sRelease / publish (push) Failing after 4m55sreleased this
2026-08-30 10:20:09 +00:00 | 36 commits to master since this releaseThe upstream query budget becomes one honest deadline. A busy network no longer blames a healthy standby for running out of time, and a query burst no longer queues invisibly until everything answers SERVFAIL at once.
Fixed
- The per-query upstream budget is now one absolute deadline, spent by everything that blocks. Waiting for a free slot on a saturated upstream now spends the query's
upstream.total_timeout_msbudget just like the exchange itself, instead of being invisible to it — under a burst, queries used to wait out their whole budget in the queue and then start attempts they could never finish. An attempt near the end of the budget runs truncated, and when a truncated attempt runs out of time that is evidence about the budget, not the upstream: it no longer counts against that upstream's health or success rate, and the query log no longer names an upstream that was given no fair chance. A field incident produced 279 rows blaming a standby whose health counters read zero for zero; those rows now attribute nothing. - A query no longer blocks behind a saturated upstream while another has capacity. Admission sweeps the upstreams in priority order and takes the first free slot; priority now means the order among upstreams that can be admitted right now, and a query blocks only when nothing has capacity — on the highest-priority eligible upstream, bounded by the remaining budget.
- Conditional forward zones spend
upstream.read_timeout_msonce per query. A UDP attempt, a truncated answer and the TCP retry now share the one budget instead of taking a fresh one each, so a slow zone resolver can no longer stretch a single query to several times the configured timeout.
Added
nxdns_upstream_budget_exhausted_total. A pool-wide counter of queries whose budget ran out — in the queue or mid-attempt — before any upstream answered. It carries no per-upstream label on purpose: running out of budget is a fact about the pool.- A configuration with more than 64 enabled upstreams is rejected at validation with a clear message, instead of tripping an internal limit at startup.
Artifacts
ef3d01e57e5a07c729aae2fa1c9ed5973984605fd4aefaf96c40960f1f0c946a nxdns-0.0.13-x86_64-linux-musl.tar.gz daf75bb747e953a498473ce0e6035326f8be4d5a2f66047667c8b83320b6793a nxdns-0.0.13-aarch64-linux-musl.tar.gz bed65338d9ef9dcc72475342ff99735262ffb93e2e15c8805d353f43853a52ab IMAGE-DIGEST.txtgit.mial.net/mokhtar/nxdns:0.0.13@sha256:75ee3fa99c48cb2302671cfb2062d01bbc303edc18d526c4f9be0887a472a1d6Commits since v0.0.8
dd5a9f6 build: bump version to 0.0.13 72cdbbd upstream: one absolute per-query budget across queueing and failover 6170571 build: bump version to 0.0.12 c847072 overview: one endpoint, live projections and a response cache (m36) 7cdb74e build: bump version to 0.0.11 4367003 changelog: 0.0.11 728b8d6 admin: draw the overview charts with visx 091962a build: bump version to 0.0.10 4fcbd0a changelog: 0.0.10 d961b15 db-mode config changes apply live in-process 17e6e93 admin: only the content region scrolls on wide screens 8a44d90 cut: schema gate — refuse to release an undisclosed querylog schema change 03149b5 ci: drop the one-insn-per-tb workaround, the qemu panic is an 11.1.0-only regression a972c8d logger tests: join every writer future before its database closes, fix the gate-open race 78d688a ci: run the aarch64 suite with one qemu insn per tb, tcg optimization falsely trips the ubsan pointer check fe5bd96 admin: live ring capacity is injectable, eviction test no longer timing-bound 1f215ac build: bump version to 0.0.9 2f86cd7 changelog: 0.0.9 releases today 51cda8b milestone 33: contract closure — samples, file-authority enumeration, dead code, bundle ceiling e5f23d5 querylog: return to the default checkpoint cadence 24521ab milestone 32: task-shaped configuration, file mode as a rendering, config status api c99a37d milestone 31: concurrent upstream exchanges, dot session reuse, queue metrics 623667e milestone 30: overview as a dashboard, explicit health contract, period aggregations 0e83477 agents: move opus-coder to the global scope fa323c7 milestone 29: activity — history, live and policy simulation on one surface 0fd6bbd milestone 28: query provenance — every logged query is exactly explainable 7e6cb50 release cut: bump-kind justfile recipe and a compiled, tested cut tool 8a17e9e admin: fix dashboard phantom scroll, drop last-failure column from upstream table 0107df5 spec: measurement window is the deployment side's callDownloads
- The per-query upstream budget is now one absolute deadline, spent by everything that blocks. Waiting for a free slot on a saturated upstream now spends the query's
-
v0.0.12
StableRelease / guard (push) Successful in 35sGates / frontend (push) Successful in 1m40sGates / test (push) Successful in 2m23sGates / test-aarch64 (push) Successful in 7m12sGates / package (push) Successful in 4m18sGates / container (push) Successful in 16sRelease / gates (push) Successful in 14m12sRelease / publish (push) Failing after 4m57sreleased this
2026-08-30 09:58:51 +00:00 | 38 commits to master since this releaseOverview stops re-reading the whole query log. One endpoint, one snapshot, pre-aggregated buckets — a 30-day view now costs the same on a month of history as on a day of it. Read the upgrade note first: it resets your query history.
Changed
- Upgrading resets your query history. The query-log schema gains the aggregate tables described below, and
querylog.dbis never migrated: the first start after the upgrade sets the old file aside (kept on disk next to the new one, named with the reason) and begins a fresh log. Settings, groups, blocklists and every other configuration are untouched. - The Overview is served by one endpoint,
GET /api/overview. It replacesGET /api/stats,/api/stats/timeseries,/api/stats/types,/api/stats/routesand/api/stats/clients, which are gone. The five panels now come from a single database snapshot, so they can no longer disagree with each other, and the page shows one loading and one error state instead of five. - Query statistics are pre-aggregated as they are written. The query log now maintains 30-minute aggregate tables in the same transaction that stores the rows, and the 24-hour, 7-day and 30-day views read those instead of scanning every logged query. The cost of opening the Overview no longer grows with the size of the log: measured at three million rows, the 30-day view went from roughly eight-tenths of a second of scanning to under fifty milliseconds, at the price of about ten percent on each background write batch and ~1.5 MB of disk. The server also keeps the most recent response per period in memory and serves repeat polls from it while nothing has changed — until new queries land, retention prunes, or the period's time window rolls forward — so on a quiet network most of the steady 30-second refreshes do no database work at all.
The Overview charts move to visx and grow up: one hover treatment across all four, honest labels, and maintained d3 math under the app's own rendering.
Changed
- The Overview charts are drawn with visx. The hand-written chart layout code is replaced by visx 4.0.0 primitives — maintained d3 math for the scales, ticks, stacking and arcs — while the rendering, colours and themes stay the app's own. The charts read as before, with four behaviour improvements: all four charts now share the same hover treatment (the per-client chart and both donuts gain the tooltip and dimming the query timeline already had, so pointing at a ring segment names it, its count and its share), an open tooltip follows a data refresh instead of showing stale counts, and it retires cleanly when the time window rolls. The admin bundle grows by about 68 KB and stays under its size budget.
- The query timeline's third series is called "Allowed". What the chart called "Other" is every query that was neither blocked nor served from cache — answered upstream, from a local record or a forward zone — so it is now named for what it is rather than for the subtraction that produces it. It stays on the chart even in a window where nothing was allowed, alongside Blocked and Cached: all three name a kind of answer a query can get, and a period where every query was blocked or cached is worth seeing.
- The client chart drops "Other" in a window where it counted nothing. That series aggregates the clients outside the top eight, so when it counts nothing there is nothing being aggregated, and a legend entry, a tooltip row and a table column that exist only to say "zero" are noise. The named clients stay even at zero, because a client that went quiet is a fact about the window.
Artifacts
f31e83a49ca21f6d97cc6c0223c6d9ca05f0f1b2432653a4b2f9a93ca0e78d29 nxdns-0.0.12-x86_64-linux-musl.tar.gz 45fe8337866989b9404f5e67945dfa989d72dc207bed3f95ea3c51dfa284b32e nxdns-0.0.12-aarch64-linux-musl.tar.gz 4cbfc00d7ca2db57a1b78587de185c2e77148eba70a2b0b4eefc97d52e53ab39 IMAGE-DIGEST.txtgit.mial.net/mokhtar/nxdns:0.0.12@sha256:a9a60ba0e64701d0252d433a794dc5a035e3122f07e9fab5b1e2e6a77924f33cCommits since v0.0.8
6170571 build: bump version to 0.0.12 c847072 overview: one endpoint, live projections and a response cache (m36) 7cdb74e build: bump version to 0.0.11 4367003 changelog: 0.0.11 728b8d6 admin: draw the overview charts with visx 091962a build: bump version to 0.0.10 4fcbd0a changelog: 0.0.10 d961b15 db-mode config changes apply live in-process 17e6e93 admin: only the content region scrolls on wide screens 8a44d90 cut: schema gate — refuse to release an undisclosed querylog schema change 03149b5 ci: drop the one-insn-per-tb workaround, the qemu panic is an 11.1.0-only regression a972c8d logger tests: join every writer future before its database closes, fix the gate-open race 78d688a ci: run the aarch64 suite with one qemu insn per tb, tcg optimization falsely trips the ubsan pointer check fe5bd96 admin: live ring capacity is injectable, eviction test no longer timing-bound 1f215ac build: bump version to 0.0.9 2f86cd7 changelog: 0.0.9 releases today 51cda8b milestone 33: contract closure — samples, file-authority enumeration, dead code, bundle ceiling e5f23d5 querylog: return to the default checkpoint cadence 24521ab milestone 32: task-shaped configuration, file mode as a rendering, config status api c99a37d milestone 31: concurrent upstream exchanges, dot session reuse, queue metrics 623667e milestone 30: overview as a dashboard, explicit health contract, period aggregations 0e83477 agents: move opus-coder to the global scope fa323c7 milestone 29: activity — history, live and policy simulation on one surface 0fd6bbd milestone 28: query provenance — every logged query is exactly explainable 7e6cb50 release cut: bump-kind justfile recipe and a compiled, tested cut tool 8a17e9e admin: fix dashboard phantom scroll, drop last-failure column from upstream table 0107df5 spec: measurement window is the deployment side's callDownloads
- Upgrading resets your query history. The query-log schema gains the aggregate tables described below, and