refactor: weekly code-quality pass — 5 fixes (2026-06-29)#312
Merged
Conversation
…on, perf) 1. AuditLogs: harden fire-and-forget publishing in EfCoreAuditHook. The background Task.Run only caught DbUpdateException, so any other publisher failure became an unobserved task exception (can tear down the process on finalization). Broaden to catch Exception + log, mark the task discarded with `_ =`, and rename the void PublishLogsAsync -> PublishLogs (it is not awaitable). 2. Specifications/Repos: propagate CancellationToken through the paging APIs. SpecRepoExtensions.ToPagedListAsync (both overloads), ModelSpecRepoExtensions.ToPagedListAsync and RepoExtensions.SpecsToPageListAsync accepted no token and could not be cancelled mid-query. Add an optional CancellationToken and flow it into X.PagedList.EF.ToPagedListAsync. 3. Specifications: replace the magic default page size in PageAsyncEnumeratorExtensions.ToPageEnumerable (100) with a named DefaultPageSize constant. 4. AzureStorage: replace the hardcoded TimeSpan.FromDays(1) SAS expiry magic value with a named DefaultSasLifetime field and clarify the comment. 5. Transformation: TokenResolver.ResolveAsync wrapped synchronous, CPU-bound reflection work in Task.Run, needlessly offloading to the thread pool inside a library. Return Task.FromResult(...) instead. Solution builds clean (0 warnings, TreatWarningsAsErrors). Transform (44), Fw.Extensions (149), Repos paging (2) and Specifications paging (31) tests pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: multica-agent <github@multica.ai>
📊 Code Coverage Report |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## dev #312 +/- ##
==========================================
+ Coverage 84.15% 84.26% +0.10%
==========================================
Files 159 159
Lines 3712 3718 +6
Branches 574 574
==========================================
+ Hits 3124 3133 +9
+ Misses 412 409 -3
Partials 176 176
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Weekly code-quality pass (2026-06-29)
Five targeted improvements found by reviewing the library source. Each is low-risk and behaviour-preserving on the success path. Categories: correctness/robustness, cancellation propagation, perf, and magic-number cleanup.
1. Harden fire-and-forget audit publishing —
EfCoreAuditHookThe background
Task.Runthat runs audit publishers only caughtDbUpdateException. Any other publisher failure escaped as an unobserved task exception, which can surface on the finalizer thread and tear down the process. Now catchesExceptionand logs it, explicitly discards the fire-and-forget task (_ =), and renames thevoidPublishLogsAsync→PublishLogs(it returns no awaitable).2. Propagate
CancellationTokenthrough paging APIsSpecRepoExtensions.ToPagedListAsync(both overloads),ModelSpecRepoExtensions.ToPagedListAsync, andRepoExtensions.SpecsToPageListAsynctook no token, so a paged query could not be cancelled mid-flight. Added an optionalCancellationTokenand flowed it intoX.PagedList.EF.ToPagedListAsync.3. Name the default page size —
PageAsyncEnumeratorExtensionsToPageEnumerable(..., int pageSize = 100)→DefaultPageSizeconstant.4. Name the default SAS lifetime —
AzureStorageBlobServiceHardcoded
TimeSpan.FromDays(1)for the default SAS expiry →DefaultSasLifetimefield, with a clearer comment.5. Drop gratuitous
Task.Run—TokenResolver.ResolveAsyncResolveis synchronous, CPU-bound reflection. Wrapping it inTask.Runinside a library wastes a thread-pool thread and adds a context switch for no benefit. ReturnsTask.FromResult(...)and lets the caller decide whether to offload. (ITokenExtractor.ExtractAsyncwas intentionally left as-is — it is fanned out viaTask.WhenAll, where the offload provides real parallelism.)Verification
dotnet build DKNet.FW.sln -c Debug→ 0 warnings, 0 errors (TreatWarningsAsErrors=true).devtoo (verified by reverting the hook) — unrelated to this change.🤖 Generated with Claude Code