a73x

3f3f6e81

docs+test: Task 11 follow-through — the test's name tells the truth, the buffer admits its guess

a73x   2026-08-12 19:56

Commit message
docs+test: Task 11 follow-through — the test's name tells the truth, the buffer admits its guess

The oneShotQuery test's name promised "and the verb is in the line" and
pinned only exit codes. Renamed to stop at what it asserts, with a clause
saying why the line itself is not pinned here: it goes to stderr rather
than being returned, and pinning a line the way `lostMsg` and
`keyRefusalBody` are pinned takes a pure function, which this is not.

`key_refusal_len`'s doc read as derived. It is not: the longest fixed
text is 53 bytes and would size itself, but the catch-all appends an
`@errorName` whose only bound is the longest error name in the binary.
So it is `open_err_len`'s kind of number — chosen to put truncation out
of reach — and the doc now says so, the way `logHint` argues its own.

The two sites that route every error to the body — `endpoint_req` and
`reportKeyRefusal` — each gain the clause that makes them readable
alone: their errors can only have come from the load, so an unclassified
one is still a key that would not read, and the body's catch-all is its
right home. `run`'s arm routes only three for the opposite reason.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

src/main.zig
Old New
@@ -756,6 +756,12 @@ fn announceKeyFrom(env: ?[]const u8, dflt: ?[]const u8) KeyResult {
756 /// was asked. That is now a fact rather than a convention: the words are 756 /// was asked. That is now a fact rather than a convention: the words are
757 /// `quic.keyRefusalBody`'s, and this half owns only the prefix and the 757 /// `quic.keyRefusalBody`'s, and this half owns only the prefix and the
758 /// `; staying on ssh` that says what the refusal cost. 758 /// `; staying on ssh` that says what the refusal cost.
759 ///
760 /// Every error is handed over, catch-all included: `announceKeyFrom` only
761 /// reaches `load_failed` with what the load returned, so an unclassified
762 /// error here is still a key that would not read — which is what the
763 /// body's fourth sentence says. `run`'s arm above routes only the three
764 /// for the opposite reason: it can afford to let the rest propagate.
759 fn reportKeyRefusal(path: []const u8, err: anyerror) void { 765 fn reportKeyRefusal(path: []const u8, err: anyerror) void {
760 var buf: [quic.key_refusal_len]u8 = undefined; 766 var buf: [quic.key_refusal_len]u8 = undefined;
761 std.debug.print( 767 std.debug.print(
@@ -1189,7 +1195,7 @@ test "askEndpointPort: a socket nobody serves answers 0, quickly" {
1189 try std.testing.expect(std.time.milliTimestamp() - t0 < 500); 1195 try std.testing.expect(std.time.milliTimestamp() - t0 < 500);
1190 } 1196 }
1191 1197
1192 test "oneShotQuery: a socket nobody serves is exit 1, and the verb is in the line" { 1198 test "oneShotQuery: a socket nobody serves is exit 1" {
1193 const testtmp = @import("testtmp"); 1199 const testtmp = @import("testtmp");
1194 var tmp = try testtmp.TmpDir.make(); 1200 var tmp = try testtmp.TmpDir.make();
1195 defer tmp.cleanup(); 1201 defer tmp.cleanup();
@@ -1200,6 +1206,11 @@ test "oneShotQuery: a socket nobody serves is exit 1, and the verb is in the lin
1200 // both are right: `stop` asked for a state the absence already satisfies, 1206 // both are right: `stop` asked for a state the absence already satisfies,
1201 // while `dump` and `stats` asked a question nothing answered. Sharing one 1207 // while `dump` and `stats` asked a question nothing answered. Sharing one
1202 // round-trip between the two query verbs must not quietly make it three. 1208 // round-trip between the two query verbs must not quietly make it three.
1209 //
1210 // The exit is all this pins. Both verbs are run because both must reach
1211 // that verdict, but the line naming the verb goes to stderr rather than
1212 // being returned, so nothing here can assert it — the way `lostMsg` and
1213 // `keyRefusalBody` are asserted is by being pure, and this is not.
1203 try std.testing.expectEqual( 1214 try std.testing.expectEqual(
1204 @as(u8, 1), 1215 @as(u8, 1),
1205 try oneShotQuery(std.testing.allocator, sock, "dump", .debug_dump, "", .dump_reply), 1216 try oneShotQuery(std.testing.allocator, sock, "dump", .debug_dump, "", .dump_reply),
src/quic.zig
Old New
@@ -122,9 +122,17 @@ pub const Key = struct {
122 } 122 }
123 }; 123 };
124 124
125 /// A buffer big enough for any refusal body: the longest sentence, a path 125 /// A buffer for one refusal body: PATH_MAX for the path, and 128 for
126 /// at PATH_MAX, and an error name. Past this the body clips — see the 126 /// everything else in the line.
127 /// truncation note on `keyRefusalBody`. 127 ///
128 /// The 128 is chosen, not derived, and the honest reason is the catch-all.
129 /// The longest fixed text is 53 bytes (` is not a key: want 32 raw bytes
130 /// or 64 hex characters`), which would size itself — but the catch-all
131 /// also appends an `@errorName`, and the only bound on that is the longest
132 /// error name in the binary, a number no source line here can name. So
133 /// this is `open_err_len`'s kind of number, picked to put truncation out
134 /// of reach, and it is `keyRefusalBody`'s clipping that makes choosing
135 /// rather than deriving safe.
128 pub const key_refusal_len = std.fs.max_path_bytes + 128; 136 pub const key_refusal_len = std.fs.max_path_bytes + 128;
129 137
130 /// The middle sentence of every key refusal, in every binary — one owner 138 /// The middle sentence of every key refusal, in every binary — one owner
src/server.zig
Old New
@@ -831,6 +831,12 @@ pub const Server = struct {
831 // and this site owns only the prefix. An operator who has seen one 831 // and this site owns only the prefix. An operator who has seen one
832 // message should not have to learn a second phrasing for it, and 832 // message should not have to learn a second phrasing for it, and
833 // this site's catch-all used to be exactly that second phrasing. 833 // this site's catch-all used to be exactly that second phrasing.
834 //
835 // Every error is routed, catch-all included, because every error
836 // here can only have come from the load: there is nothing else in
837 // this expression to have failed. So an unclassified one is still a
838 // key that would not read, which is exactly what the body's fourth
839 // sentence says.
834 const key = quic.Key.load(key_path) catch |err| { 840 const key = quic.Key.load(key_path) catch |err| {
835 var buf: [quic.key_refusal_len]u8 = undefined; 841 var buf: [quic.key_refusal_len]u8 = undefined;
836 std.debug.print( 842 std.debug.print(