House rules: numbers through one formatter, no made-up server errors, and the rules fail the build
Build / Build (push) Successful in 33s

- Every number shown on a page goes through NumbersExtensions: counts,
  percentages, the nerd readouts and the values written into a style.
- A failure the client builds itself (offline, timeout, retries run out, an
  answer it can't read) is a 400 that names its kind; only a server's own 5XX
  passes through.
- Login, sign-up, recovery and password confirmations leave autocomplete to
  the browser, so it can offer the saved login.
- The Daisy components start with empty lists and attributes, and a
  decorative image still renders alt="".
- Arasaka.HouseRules.Analyzers checks all of this in every build, together
  with PrivaPub.ClientModels.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W4YtEJrgxG12Pc39Fai8Bd
This commit is contained in:
thepraandClaude Opus 5.5 committed 2026-11-10 01:26:39 +01:00
1 parent 697b2c8897
commit 3827d903a3
37 files changed
+165 -111

No files matched your search

+8 -8
View File
@@ -159,7 +159,7 @@ namespace decePubClient.Services
if (string.IsNullOrEmpty(token?.AccessToken))
{
response.Dispose();
return (SUtility.ClassifiedFailure(FailureCodes.ServerError, localizer["The server sent an invalid response."], HttpStatusCode.BadGateway), null);
return (SUtility.ClassifiedFailure(FailureCodes.ServerError, localizer["The server sent an invalid response."], HttpStatusCode.BadRequest), null);
}
return (response, token.AccessToken);
@@ -205,7 +205,7 @@ namespace decePubClient.Services
{
await logger.ProcessError(ex, where, cancellationToken);
return SUtility.ClassifiedFailure(FailureCodes.ClientError,
localizer["The request could not be prepared. Reload the page and try again."], HttpStatusCode.ServiceUnavailable);
localizer["The request could not be prepared. Reload the page and try again."], HttpStatusCode.BadRequest);
}
var delay = attempt < RetryRampUpDelaysMs.Length ? RetryRampUpDelaysMs[attempt] : RetryIndefiniteDelayMs;
@@ -216,7 +216,7 @@ namespace decePubClient.Services
if (transportException is not null)
return await DescribeUnreachable(transportException, attempt + 1, cancellationToken);
return SUtility.ClassifiedFailure(FailureCodes.RetriesExhausted,
localizer["The server is still not answering after {0} attempts. Try again later.", attempt + 1], HttpStatusCode.ServiceUnavailable);
localizer["The server is still not answering after {0} attempts. Try again later.", attempt + 1], HttpStatusCode.BadRequest);
}
await logger.ProcessWarning($"Attempt {attempt + 1} failed, retrying in {delay}ms. {failure}", where, cancellationToken);
@@ -245,18 +245,18 @@ namespace decePubClient.Services
{
if (!await statusService.IsOnline(cancellationToken))
return SUtility.ClassifiedFailure(FailureCodes.DeviceOffline,
localizer["This device is offline. Check the connection and try again."], HttpStatusCode.ServiceUnavailable);
localizer["This device is offline. Check the connection and try again."], HttpStatusCode.BadRequest);
if (exception is TaskCanceledException { InnerException: TimeoutException })
return SUtility.ClassifiedFailure(FailureCodes.Timeout,
localizer["The server took too long to answer. Try again later."], HttpStatusCode.ServiceUnavailable);
localizer["The server took too long to answer. Try again later."], HttpStatusCode.BadRequest);
if (attempts > 1)
return SUtility.ClassifiedFailure(FailureCodes.RetriesExhausted,
localizer["The server is still not answering after {0} attempts. Try again later.", attempts], HttpStatusCode.ServiceUnavailable);
localizer["The server is still not answering after {0} attempts. Try again later.", attempts], HttpStatusCode.BadRequest);
return SUtility.ClassifiedFailure(FailureCodes.ApiUnreachable,
localizer["The server can't be reached. Try again later."], HttpStatusCode.ServiceUnavailable);
localizer["The server can't be reached. Try again later."], HttpStatusCode.BadRequest);
}
Task<HttpResponseMessage> SendAnonymousRequest(Func<HttpRequestMessage> requestFactory, CancellationToken cancellationToken) =>
@@ -403,7 +403,7 @@ namespace decePubClient.Services
using var timeout = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
timeout.CancelAfter(request.Content is MultipartContent ? UploadTimeout : RequestTimeout);
var started = Stopwatch.GetTimestamp();
HttpResponseMessage response;
var response = default(HttpResponseMessage);
try
{
response = await httpClient.SendAsync(request, timeout.Token);