Skip to content

fix: progress display alignment and SYSLIB0060#29

Merged
woutervanranst merged 7 commits into
masterfrom
branch-jaw
Mar 28, 2026
Merged

fix: progress display alignment and SYSLIB0060#29
woutervanranst merged 7 commits into
masterfrom
branch-jaw

Conversation

@woutervanranst
Copy link
Copy Markdown
Owner

@woutervanranst woutervanranst commented Mar 28, 2026

Summary

  • Replace obsolete Rfc2898DeriveBytes constructor with Rfc2898DeriveBytes.Pbkdf2 (fixes SYSLIB0060 warning)
  • Refactor per-file and TAR bundle progress rows to use a Spectre borderless table with SplitSizePair helper
  • Fix decimal separator (locale-invariant formatting) and clamp percentage display to 100%
  • Fix column alignment: collect all rows first, compute max widths, then pre-pad with PadLeft/PadRight — Spectre NoBorder does not pad cells so alignment must be done manually

Commits

  • 45f1bf1 fix: replace obsolete Rfc2898DeriveBytes constructor (SYSLIB0060)
  • bc4241c refactor: use Spectre Table for per-file and TAR bundle progress rows
  • a057a33 fix: use InvariantCulture and clamp pct to 100%
  • b6d459f fix: use fixed 2-decimal format in SplitSizePair
  • d1f9c6d fix: pre-pad size columns manually for true decimal alignment

Summary by CodeRabbit

  • New Features

    • Per-file progress tracking with granular event details during file enumeration
    • TAR bundle progress monitoring and lifecycle tracking in the display
  • Refactor

    • Improved progress display with aligned columns and live stage counters for scanning, hashing, and uploading phases
    • Enhanced queue depth monitoring for hash and upload operations
    • Updated event semantics for cleaner progress state management

Sync all three delta specs for the progress-display-redesign change:
- progress-display: replace FileState enum (adds Hashed, removes QueuedInTar/UploadingTar/TarId), add TrackedTar entity, update handlers table and aggregate counters for new scanning/TAR events
- archive-pipeline: add per-file FileScannedEvent + ScanCompleteEvent, TarBundleStartedEvent notification, TAR upload ProgressStream wiring, OnHashQueueReady/OnUploadQueueReady callbacks on ArchiveOptions, replace TarBundleSealingEvent-with-content-hashes with new event model
- cli: replace archive display layout with 3-section design (scanning header, hashing with queue depth/dedup, uploading with queue depth, TAR bundle lines), update progress callback wiring for dual TrackedFile/TrackedTar lookup, update streaming events list
Replace manual PadLeft string interpolation in BuildArchiveDisplay with a
borderless 7-column Spectre Table (name | bar | state | % | current | / | total+unit).
Add SplitSizePair helper that returns (current, total, unit) strings sharing
the unit of the total so each column can be independently aligned.
Remove FormatSizePair (superseded by SplitSizePair).
SplitSizePair now formats values with CultureInfo.InvariantCulture so
decimal separators are always '.' regardless of system locale.
All percentage displays are clamped to 100 before formatting to prevent
>100% showing when uploaded bytes slightly exceed the recorded TAR size.
Spectre NoBorder table does not pad cells, so right-aligning current/total
in separate columns had no effect. Fix: collect all row data first, compute
max widths for cur, tot, pct, and stateLabel, then pad with PadLeft/PadRight
before inserting into a single pre-formatted size column.
@codecov
Copy link
Copy Markdown

codecov Bot commented Mar 28, 2026

Codecov Report

❌ Patch coverage is 90.76923% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 82.12%. Comparing base (b4ba47c) to head (d1f9c6d).
⚠️ Report is 9 commits behind head on master.

Files with missing lines Patch % Lines
src/Arius.Cli/CliBuilder.cs 90.00% 0 Missing and 6 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master      #29      +/-   ##
==========================================
+ Coverage   82.04%   82.12%   +0.07%     
==========================================
  Files          27       27              
  Lines        3002     3026      +24     
  Branches      354      360       +6     
==========================================
+ Hits         2463     2485      +22     
  Misses        457      457              
- Partials       82       84       +2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 28, 2026

📝 Walkthrough

Walkthrough

The PR updates archive pipeline event semantics to emit per-file scan events and new tar bundle lifecycle events, adds queue-depth callbacks to ArchiveOptions, refactors progress state to track TAR bundles as separate entities from files, updates CLI progress rendering for the new model, and simplifies PBKDF2 key derivation using a single static call.

Changes

Cohort / File(s) Summary
Archive Pipeline Specification
openspec/specs/archive-pipeline/spec.md
Replaces batch FileScannedEvent(long TotalFiles) with per-file FileScannedEvent(string RelativePath, long FileSize), adds ScanCompleteEvent(long TotalFiles, long TotalBytes) and TarBundleStartedEvent(), introduces ArchiveOptions.OnHashQueueReady and ArchiveOptions.OnUploadQueueReady callbacks, and specifies ProgressStream wiring for TAR uploads reporting cumulative uncompressed bytes.
Progress Display State Specification
openspec/specs/progress-display/spec.md
Refactors FileState enum from Hashing, QueuedInTar, UploadingTar, Uploading, Done to Hashing, Hashed, Uploading, Done, introduces new TrackedTar entity with TarState and related fields, removes TrackedFile.TarId, changes ContentHashToPath to map to ConcurrentBag<string> for multiple file matches, and adds FilesScanned, BytesScanned, ScanComplete, FilesUnique, HashQueueDepth, and UploadQueueDepth to ProgressState.
CLI Display Specification
openspec/specs/cli/spec.md
Updates BuildArchiveDisplay to return Rows(...) renderable with both file lines (for Hashing/Uploading states only) and TAR bundle lines from TrackedTars, revises stage headers to show live queue depths and scan/hash/upload progress counters, and specifies dual-lookup progress callback wiring for both large file and TAR uploads.
CLI Progress Rendering
src/Arius.Cli/CliBuilder.cs
Consolidates per-file and TAR bundle rendering into a single borderless Table with aligned columns, refactors percentage formatting to use Math.Min(pct*100, 100) and CultureInfo.InvariantCulture, adds new exported helper SplitSizePair(long current, long total) returning formatted size strings with shared unit symbol, and removes previous "humanized" and state-specific text formatting.
Encryption Key Derivation
src/Arius.Core/Encryption/PassphraseEncryptionService.cs
Replaces instantiation of Rfc2898DeriveBytes with static Rfc2898DeriveBytes.Pbkdf2(...) call, explicitly requests KeySize + IvSize derived material length, and splits result via slicing into AES key and IV instead of two sequential GetBytes calls.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix: progress display alignment and SYSLIB0060' accurately describes two main fixes in the PR: addressing SYSLIB0060 deprecation warning and fixing progress display alignment/formatting issues.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch branch-jaw

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
openspec/specs/progress-display/spec.md (1)

247-250: ⚠️ Potential issue | 🟡 Minor

Add language specifier to fenced code block.

The code block showing RestoreFileEvent record definition is missing a language specifier.

Proposed fix
 **`RestoreFileEvent` record** (internal):
-```
+```csharp
 RestoreFileEvent(string RelativePath, long FileSize, bool Skipped)
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against the current code and only fix it if needed.

In @openspec/specs/progress-display/spec.md around lines 247 - 250, The fenced
code block for the RestoreFileEvent record is missing a language specifier;
update the markdown where the RestoreFileEvent(string RelativePath, long
FileSize, bool Skipped) record is shown to use a fenced code block with the
"csharp" language (i.e., change the opening triple backticks to ```csharp) so
syntax highlighting and tooling recognize the C# record definition.


</details>

</blockquote></details>

</blockquote></details>
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/Arius.Cli/CliBuilder.cs`:
- Around line 1026-1036: SplitSizePair can produce NaN when
totalInfo.LargestWholeNumberValue is 0; change the divisor and currentVal
calculations to guard against a zero largest-whole-number value by checking
totalInfo.LargestWholeNumberValue > 0 before computing divisor = (double)total /
totalInfo.LargestWholeNumberValue, otherwise set divisor = 1.0, then compute
currentVal = divisor > 0 ? current / divisor : 0.0 and keep totalVal =
totalInfo.LargestWholeNumberValue (which may be 0) so formatting remains safe;
update only the computations in SplitSizePair (variables
totalInfo.LargestWholeNumberValue, divisor, currentVal, totalVal) to implement
this guard.

---

Outside diff comments:
In `@openspec/specs/progress-display/spec.md`:
- Around line 247-250: The fenced code block for the RestoreFileEvent record is
missing a language specifier; update the markdown where the
RestoreFileEvent(string RelativePath, long FileSize, bool Skipped) record is
shown to use a fenced code block with the "csharp" language (i.e., change the
opening triple backticks to ```csharp) so syntax highlighting and tooling
recognize the C# record definition.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: fc2be98a-c69a-446d-af17-c19b1c0cb8d4

📥 Commits

Reviewing files that changed from the base of the PR and between 6b83842 and d1f9c6d.

📒 Files selected for processing (12)
  • openspec/changes/archive/2026-03-28-progress-display-redesign/.openspec.yaml
  • openspec/changes/archive/2026-03-28-progress-display-redesign/design.md
  • openspec/changes/archive/2026-03-28-progress-display-redesign/proposal.md
  • openspec/changes/archive/2026-03-28-progress-display-redesign/specs/archive-pipeline/spec.md
  • openspec/changes/archive/2026-03-28-progress-display-redesign/specs/cli/spec.md
  • openspec/changes/archive/2026-03-28-progress-display-redesign/specs/progress-display/spec.md
  • openspec/changes/archive/2026-03-28-progress-display-redesign/tasks.md
  • openspec/specs/archive-pipeline/spec.md
  • openspec/specs/cli/spec.md
  • openspec/specs/progress-display/spec.md
  • src/Arius.Cli/CliBuilder.cs
  • src/Arius.Core/Encryption/PassphraseEncryptionService.cs

Comment on lines +1026 to +1036
internal static (string current, string total, string unit) SplitSizePair(long current, long total)
{
var totalInfo = total.Bytes();
var unit = totalInfo.LargestWholeNumberSymbol;
var divisor = total > 0 ? (double)total / totalInfo.LargestWholeNumberValue : 1.0;
var currentVal = divisor > 0 ? current / divisor : 0.0;
var totalVal = totalInfo.LargestWholeNumberValue;
return (currentVal.ToString("0.00", CultureInfo.InvariantCulture),
totalVal .ToString("0.00", CultureInfo.InvariantCulture),
unit);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Potential division-by-zero edge case in SplitSizePair.

When total is 0, totalInfo.LargestWholeNumberValue will be 0, and the divisor calculation (double)total / totalInfo.LargestWholeNumberValue becomes 0 / 0 which is NaN. This causes currentVal = current / divisor to also be NaN, resulting in display issues.

Proposed fix
 internal static (string current, string total, string unit) SplitSizePair(long current, long total)
 {
+    if (total <= 0)
+        return ("0.00", "0.00", "B");
+
     var totalInfo  = total.Bytes();
     var unit       = totalInfo.LargestWholeNumberSymbol;
     var divisor    = total > 0 ? (double)total / totalInfo.LargestWholeNumberValue : 1.0;
     var currentVal = divisor > 0 ? current / divisor : 0.0;
     var totalVal   = totalInfo.LargestWholeNumberValue;
     return (currentVal.ToString("0.00", CultureInfo.InvariantCulture),
             totalVal  .ToString("0.00", CultureInfo.InvariantCulture),
             unit);
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
internal static (string current, string total, string unit) SplitSizePair(long current, long total)
{
var totalInfo = total.Bytes();
var unit = totalInfo.LargestWholeNumberSymbol;
var divisor = total > 0 ? (double)total / totalInfo.LargestWholeNumberValue : 1.0;
var currentVal = divisor > 0 ? current / divisor : 0.0;
var totalVal = totalInfo.LargestWholeNumberValue;
return (currentVal.ToString("0.00", CultureInfo.InvariantCulture),
totalVal .ToString("0.00", CultureInfo.InvariantCulture),
unit);
}
internal static (string current, string total, string unit) SplitSizePair(long current, long total)
{
if (total <= 0)
return ("0.00", "0.00", "B");
var totalInfo = total.Bytes();
var unit = totalInfo.LargestWholeNumberSymbol;
var divisor = total > 0 ? (double)total / totalInfo.LargestWholeNumberValue : 1.0;
var currentVal = divisor > 0 ? current / divisor : 0.0;
var totalVal = totalInfo.LargestWholeNumberValue;
return (currentVal.ToString("0.00", CultureInfo.InvariantCulture),
totalVal .ToString("0.00", CultureInfo.InvariantCulture),
unit);
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/Arius.Cli/CliBuilder.cs` around lines 1026 - 1036, SplitSizePair can
produce NaN when totalInfo.LargestWholeNumberValue is 0; change the divisor and
currentVal calculations to guard against a zero largest-whole-number value by
checking totalInfo.LargestWholeNumberValue > 0 before computing divisor =
(double)total / totalInfo.LargestWholeNumberValue, otherwise set divisor = 1.0,
then compute currentVal = divisor > 0 ? current / divisor : 0.0 and keep
totalVal = totalInfo.LargestWholeNumberValue (which may be 0) so formatting
remains safe; update only the computations in SplitSizePair (variables
totalInfo.LargestWholeNumberValue, divisor, currentVal, totalVal) to implement
this guard.

@woutervanranst woutervanranst merged commit d5d5721 into master Mar 28, 2026
8 checks passed
@woutervanranst woutervanranst deleted the branch-jaw branch March 28, 2026 14:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant