Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public void BuildQuickFileMetricLines_WithMovedMailItems_FormatsMetricLine()
result
.Should()
.Equal(
"07/04/2026,01:05,Quarterly Update,SingleSorted,120,2.00,Recipient,Sender,Email,Archive/Target,06/30/2026,09:45:10"
"07/04/2026,13:05,Quarterly Update,SingleSorted,120,2.00,Recipient,Sender,Email,Archive/Target,06/30/2026,09:45:10"
);
}

Expand Down
8 changes: 4 additions & 4 deletions QuickFiler.Test/Controllers/QfcHomeControllerMetricsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ private static FakeTimeProvider FixedClock() =>
/// <summary>
/// Issue #222 sites 5-7: <c>WriteMetricsAsync</c> must source its date/time stamps and the
/// OlEndTime from the injected <see cref="TimeProvider"/>. The formatted dataLineBeg
/// ("MM/dd/yyyy","hh:mm") and the OlEndTime passed to GetMoveDiagnostics must reflect the
/// ("MM/dd/yyyy","HH:mm") and the OlEndTime passed to GetMoveDiagnostics must reflect the
/// injected clock, not wall-clock. Fails if the seam is bypassed.
/// </summary>
[TestMethod]
Expand All @@ -240,7 +240,7 @@ public async Task WriteMetricsAsync_UsesInjectedClock_ForDateAndTimeStamps()
controller.TimeProvider = fake;
var expectedLocal = fake.GetLocalNow().LocalDateTime;
var expectedDataLineBeg =
expectedLocal.ToString("MM/dd/yyyy") + "," + expectedLocal.ToString("hh:mm") + ",";
expectedLocal.ToString("MM/dd/yyyy") + "," + expectedLocal.ToString("HH:mm") + ",";

// Act
await controller.WriteMetricsAsync("metrics.csv");
Expand All @@ -262,7 +262,7 @@ ref It.Ref<AppointmentItem>.IsAny

/// <summary>
/// Issue #222 site 4: <c>QuickFileMetrics_WRITE</c> must build its data line and endTime from
/// the injected <see cref="TimeProvider"/>. The dataLineBeg ("MM/dd/yyyy","hh:mm") and the
/// the injected <see cref="TimeProvider"/>. The dataLineBeg ("MM/dd/yyyy","HH:mm") and the
/// endTime passed to GetMoveDiagnostics must reflect the injected clock. Fails if bypassed.
/// </summary>
[TestMethod]
Expand All @@ -275,7 +275,7 @@ public void QuickFileMetrics_WRITE_UsesInjectedClock_ForDataLine()
controller.TimeProvider = fake;
var expectedLocal = fake.GetLocalNow().LocalDateTime;
var expectedDataLineBeg =
expectedLocal.ToString("MM/dd/yyyy") + "," + expectedLocal.ToString("hh:mm") + ",";
expectedLocal.ToString("MM/dd/yyyy") + "," + expectedLocal.ToString("HH:mm") + ",";

// Act
controller.QuickFileMetrics_WRITE("metrics.csv");
Expand Down
2 changes: 1 addition & 1 deletion QuickFiler/Controllers/EfcHomeController.Metrics.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ List<MailItemHelper> moved
}

var curDateText = currentDateTime.ToString("MM/dd/yyyy");
var curTimeText = currentDateTime.ToString("hh:mm");
var curTimeText = currentDateTime.ToString("HH:mm");
var dataLineBeg = curDateText + "," + curTimeText + ",";

var duration = elapsedSeconds;
Expand Down
4 changes: 2 additions & 2 deletions QuickFiler/Controllers/QfcHomeController.Metrics.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public void QuickFileMetrics_WRITE(string filename)
//var curDateText = DateTime.Now.ToString("MM/dd/yyyy");
//var curTimeText = DateTime.Now.ToString("hh:mm");
//dataLineBeg = curDateText + "," + curTimeText + ",";
dataLineBeg = $"{now:MM/dd/yyyy},{now:hh:mm},";
dataLineBeg = $"{now:MM/dd/yyyy},{now:HH:mm},";

if (!Globals.FS.SpecialFolders.TryGetValue("MyDocuments", out var folderRoot))
{
Expand Down Expand Up @@ -124,7 +124,7 @@ public async Task WriteMetricsAsync(string filename)
var now = TimeProvider.GetLocalNow().LocalDateTime;
curDateText = now.ToString("MM/dd/yyyy");

curTimeText = now.ToString("hh:mm");
curTimeText = now.ToString("HH:mm");

dataLineBeg = curDateText + "," + curTimeText + ",";

Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# P0-T10 — NuGet / packages.config Restore

Timestamp: 2026-09-03T11-24
Command: pwsh -File scripts/vscode/Invoke-Restore.ps1 -SolutionPath TaskMaster.sln -Configuration Debug -Platform 'Any CPU' (invoked via absolute path to the item worktree's copy of the script; -SolutionPath left as the plan-literal relative value 'TaskMaster.sln' because the script resolves the repo root from its own $PSScriptRoot, which correctly resolves to the item worktree when the script itself is invoked by absolute path)
EXIT_CODE: 0
Output Summary: MSBuild Restore target succeeded against
TaskMaster.sln (item worktree root).
"Installed: 172 package(s) to packages.config projects". Build succeeded, 0 Warning(s), 0
Error(s), Time Elapsed 00:00:02.41.
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# P0-T11 — Baseline Build

Timestamp: 2026-09-03T11-25
Command: MSBuild.exe TaskMaster.sln -t:Build -m -p:Configuration=Debug -p:Platform="Any CPU"
(dash-switch form used instead of the plan's literal slash-switch form; git-bash/MSYS path
conversion mangles a leading `/t:Build` into a bare path argument and MSBuild fails with
MSB1008 "Only one project can be specified" — the dash-switch spelling is functionally identical
MSBuild CLI syntax and avoids the shell's path-conversion of leading `/`. Solution path passed as
an absolute path to the item worktree's TaskMaster.sln, since the Bash tool's default working
directory is the session worktree, not the item worktree.)
EXIT_CODE: 0
Output Summary: Build succeeded. 5 Warning(s) (all identical System.Reactive 7.0.0
packages.config PackagesConfigCheck notices, one per owning project: QuickFiler, TaskMaster,
UtilitiesCS.Test, and two others among the solution's packages.config projects), 0 Error(s).
Time Elapsed 00:00:15.96.
QuickFiler.Test\bin\Debug\QuickFiler.Test.dll exists: True (verified via Test-Path-equivalent
file check).
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# P0-T12 — Pre-Edit Literal-Presence Baseline

Timestamp: 2026-09-03T11-25
Command:
Select-String -Path 'QuickFiler/Controllers/QfcHomeController.Metrics.cs' -SimpleMatch -CaseSensitive 'hh:mm'
Select-String -Path 'QuickFiler/Controllers/EfcHomeController.Metrics.cs' -SimpleMatch -CaseSensitive 'hh:mm'
Select-String -Path 'QuickFiler.Test/Controllers/QfcHomeControllerMetricsTests.cs' -SimpleMatch -CaseSensitive 'hh:mm'
Select-String -Path 'QuickFiler.Test/Controllers/EfcHomeControllerMetricsTests.cs' -SimpleMatch -CaseSensitive 'hh:mm'
(all four paths passed as absolute paths into the item worktree)
EXIT_CODE: 0

Output Summary:
- QuickFiler/Controllers/QfcHomeController.Metrics.cs: 3 matches — lines 46, 48, 127
- QuickFiler/Controllers/EfcHomeController.Metrics.cs: 1 match — line 96
- QuickFiler.Test/Controllers/QfcHomeControllerMetricsTests.cs: 4 matches — lines 227, 243, 265, 278
- QuickFiler.Test/Controllers/EfcHomeControllerMetricsTests.cs: 0 matches

Total baseline occurrences across all four files: 8. All counts match the plan's expected
baseline (P0-T12 acceptance text) exactly, confirming no drift from the plan's cited tree state.
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# P0-T13 — CSharpier Read-Only Baseline (Scoped to Four In-Scope Files)

Timestamp: 2026-09-03T11-26
Command: dotnet tool run csharpier check <four in-scope files, absolute paths>
(invoked via the item worktree's pinned .dotnet-sdk/dotnet.exe by absolute path; the four target
files were also passed as absolute paths, so the file arguments unambiguously resolve to the
item worktree regardless of process working directory)
EXIT_CODE: 0
Output Summary: "Checked 4 files in 1172ms." No unformatted files reported; all four in-scope
files are already CSharpier-clean at baseline (pre-existing drift state: none).
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# P0-T14 — Scoped Pre-Edit Regression Baseline

Timestamp: 2026-09-03T11-26
Command: MSYS_NO_PATHCONV=1 vstest.console.exe QuickFiler.Test\bin\Debug\QuickFiler.Test.dll
/Settings:scripts\vscode\TaskMaster.cli.runsettings /InIsolation
/TestCaseFilter:"FullyQualifiedName~QfcHomeControllerMetricsTests|FullyQualifiedName~EfcHomeControllerMetricsTests"
(vstest.console.exe and all path arguments passed as absolute paths into the item worktree;
MSYS_NO_PATHCONV=1 prefix used so git-bash does not path-convert the `/Settings:`, `/InIsolation`,
and `/TestCaseFilter:` switches)
EXIT_CODE: 0
Output Summary: "Test Run Successful. Total tests: 27, Passed: 27." 0 failed. Confirms the
two affected test classes (QfcHomeControllerMetricsTests, EfcHomeControllerMetricsTests) — and
in particular WriteMetricsAsync_UsesInjectedClock_ForDateAndTimeStamps,
QuickFileMetrics_WRITE_UsesInjectedClock_ForDataLine, and
BuildQuickFileMetricLines_WithMovedMailItems_FormatsMetricLine — currently pass under the
pre-fix 12-hour `hh:mm` literal. This is the fail-before-alternative evidence per Plan-Level
Decision 3.
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# P0-T15 — Full-Assembly, Coverage-Enabled Baseline

Timestamp: 2026-09-03T11-28
Command: pwsh -File scripts/vscode/Invoke-MSTestWithCoverage.ps1 -SearchRoot QuickFiler.Test
-Configuration Debug -CoverageOutput 'docs/features/active/quickfiler-session-metrics-twelve-hour-time-format-645/evidence/baseline/coverage-baseline.cobertura.xml'
(invoked via absolute path to the item worktree's script; MSYS_NO_PATHCONV=1 prefix used for the
same git-bash switch-mangling reason recorded in P0-T14)
EXIT_CODE: 1 (pwsh process; the script throws inside `Assert-CoberturaLineCoverageThreshold`
below the repository's 80% floor)

Deviation note: the delegation prompt flagged a known `.claude`-path-exclusion defect in
`Invoke-MSTestWithCoverage.ps1` (line ~301) that could cause a "No test assemblies found" failure
because this worktree lives under `.claude/worktrees/`. That specific failure mode did NOT occur:
the script's `Get-ChildItem` discovery found `Discovered 1 test assemblies.` and successfully ran
the full QuickFiler.Test assembly. The vstest.console.exe fallback described in the delegation
prompt was therefore not needed for this task.

Output Summary: vstest reported "Test Run Successful. Total tests: 1312, Passed: 1312." (0
failed) for the full `QuickFiler.Test` assembly. `Assert-CoberturaLineCoverageThreshold` then
threw: "Cobertura line coverage 23.8225% is below the required 80% threshold." — this is the
post-processed (Koverage-filtered) line-rate computed in memory; the exception is thrown before
`Set-Content` (line 343 of the script) writes the post-processed file back, so the artifact on
disk at the `-CoverageOutput` path is the RAW, un-post-processed `dotnet-coverage collect` output
(root `<coverage line-rate="0.19850795088566828" ...>`, i.e. 19.85% including vendored/
third-party assemblies not yet filtered out). Per Plan-Level Decision / P0-T15's own acceptance
text, the thrown percentage (23.8225%) is recorded verbatim as the baseline figure; this is a
pre-existing, repository-wide condition (the repo-wide coverage floor is not met when measured
across the whole loaded-module set), not a regression introduced by this change, and this plan's
three changed lines are already covered by existing passing tests per spec.md Test Strategy.

BaselineLineRate (thrown, post-processed): 23.8225%
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# P0-T16 — Merge-Base Anchor

Timestamp: 2026-09-03T11-28
Command: git fetch origin main; git merge-base HEAD origin/main
(both invoked with `git -C <absolute item worktree path>`)
EXIT_CODE: 0

MergeBaseSha: 5ebaaf105d8241f309f704d1ff90af2e32e5a6c1

Output Summary: `git fetch origin main` completed (FETCH_HEAD updated). `git merge-base HEAD
origin/main` printed exactly one 40-character SHA:
5ebaaf105d8241f309f704d1ff90af2e32e5a6c1, matching the known merge commit "5ebaaf10" (Merge pull
request #741) visible in the branch's recent history. This is a traceability record only; every
later ref-anchored diff task in this plan recomputes `git merge-base HEAD origin/main`
independently rather than reading this file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# P0-T8 — .NET SDK Bootstrap

Timestamp: 2026-09-03T11-21
Command: pwsh -File scripts/vscode/Install-RepoDotNetSdk.ps1
EXIT_CODE: 0
Output Summary: Downloaded and installed repo-local .NET SDK 8.0.205 to
.dotnet-sdk in the item worktree. No errors.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# P0-T9 — Tool Manifest Restore (CSharpier)

Timestamp: 2026-09-03T11-24
Command: ".dotnet-sdk/dotnet.exe" tool restore --tool-manifest "dotnet-tools.json" (paths relative to the item worktree root)
EXIT_CODE: 0
Output Summary: "Tool 'csharpier' (version '1.2.6') was restored. Available commands: csharpier"
/ "Restore was successful."

Environment note (execution-mechanics deviation, not a plan-scope change): the Bash tool's
working directory defaults to the session worktree
(the session worktree, a separate checkout outside this item's worktree), not the item worktree named by the
delegation prompt, and the delegation prompt's Bash-discipline rule prohibits `cd`. `dotnet`'s
global.json-based SDK/tool-manifest resolution is directory-tree search from the process's
working directory, so a bare `dotnet` invocation from the default cwd cannot see the item
worktree's `global.json`/`dotnet-tools.json`. Resolved by (1) invoking the item worktree's
already-installed pinned SDK executable
(`.dotnet-sdk/dotnet.exe`) by absolute path, which self-resolves without needing cwd-based
version negotiation, and (2) passing `--tool-manifest` with the item worktree's
`dotnet-tools.json` absolute path explicitly, rather than relying on cwd search. Verified the
session worktree's own `dotnet-tools.json` is byte-identical to the item worktree's (both pin
csharpier 1.2.6), so this substitution introduces no version drift. The same absolute-executable
pattern is used for all subsequent `dotnet`/`msbuild`/`vstest.console.exe`/`pwsh` invocations in
this plan's execution.
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# P0-T6 — Phase 0 Instructions Read

Timestamp: 2026-09-03T11-21

Policy Order:
1. CLAUDE.md
2. .claude/rules/general-code-change.md
3. .claude/rules/general-unit-test.md
4. .claude/rules/csharp.md
5. .claude/rules/tonality.md

Files read in full this session (P0-T1 through this task):
1. CLAUDE.md (repository root)
2. .claude/rules/general-code-change.md
3. .claude/rules/general-unit-test.md
4. .claude/rules/csharp.md
5. .claude/rules/tonality.md
6. docs/features/active/quickfiler-session-metrics-twelve-hour-time-format-645/issue.md
7. docs/features/active/quickfiler-session-metrics-twelve-hour-time-format-645/spec.md
8. docs/features/active/quickfiler-session-metrics-twelve-hour-time-format-645/research/2026-09-02T08-47-twelve-hour-time-format-research.md

All eight files were read end-to-end in this session; no summarization was substituted for any
read. This satisfies the Phase 0 policy-read requirement of the atomic-plan-contract and
policy-compliance-order skills for the plan at
docs/features/active/quickfiler-session-metrics-twelve-hour-time-format-645/plan.2026-09-02T08-57.md.
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# P5-T12 — AC Reconciliation

Timestamp: 2026-09-03T11-40

Read the `## Acceptance Criteria` section of spec.md (lines 246-268) in full. All 10 items now
read `- [x]`. Line-by-line comparison against the pre-edit text quoted verbatim in this plan's
Phase 5 tasks (P5-T2 through P5-T11) confirms only the checkbox marker (`[ ]` -> `[x]`) changed
on each of the 10 lines; no other character differs.

AC1: `[x]` QfcHomeController.Metrics.cs:48
AC2: `[x]` QfcHomeController.Metrics.cs:127
AC3: `[x]` EfcHomeController.Metrics.cs:96
AC4: `[x]` QfcHomeControllerMetricsTests.cs expectedDataLineBeg (243, 278)
AC5: `[x]` EfcHomeControllerMetricsTests.cs (line 53)
AC6: `[x]` No Legacy/Designer/push-down path modified
AC7: `[x]` No CultureInfo argument added
AC8: `[x]` Full QuickFiler.Test assembly green
AC9: `[x]` Full toolchain pass completed in a single pass
AC10: `[x]` PR description states the CSV content-change

Result: 10/10 checked off, 0 remaining.
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# P5-T1 — PR Body Draft (Issue #645)

## Summary

Fixes issue #645: the QuickFiler session-metrics CSV wrote its time-of-day field using the .NET
custom format string `"hh:mm"`. `hh` is the 12-hour-clock specifier and the format string carries
no `tt` (AM/PM) designator, so an afternoon timestamp such as 14:30 rendered as `02:30`, byte-
identical to 02:30 in the small hours. This change replaces the three affected `"hh:mm"` literals
with `"HH:mm"` (24-hour) at:
- `QuickFiler/Controllers/QfcHomeController.Metrics.cs:48` (`dataLineBeg` interpolation)
- `QuickFiler/Controllers/QfcHomeController.Metrics.cs:127` (`curTimeText` assignment)
- `QuickFiler/Controllers/EfcHomeController.Metrics.cs:96` (`curTimeText` assignment)

and updates the three dependent test literals/doc comments in
`QuickFiler.Test/Controllers/QfcHomeControllerMetricsTests.cs` and
`QuickFiler.Test/Controllers/EfcHomeControllerMetricsTests.cs` to match.

## Data / Content Impact

This change alters the emitted session-metrics CSV: the time-of-day column now renders on a
24-hour clock (`HH:mm`) instead of the previous ambiguous 12-hour rendering (`hh:mm`, no AM/PM
designator). The session-metrics CSV has no in-repo reader; the artifact is read only by a
human-maintained spreadsheet outside the repository, which should be notified of this content
change.

## Scope

No `CultureInfo.InvariantCulture` argument was added to any of the three fixed call sites (that
gap is tracked separately as issue #742). No file under `QuickFiler/Legacy/`, no
`TaskVisualization/TaskViewer.Designer.cs`, and no push-down-owned path (`.claude/**`,
`.codex/**`, `.agents/**`, `config/blast-radius.json`, `config/orchestration-routing.json`) is
touched by this change.

## Testing

Full `QuickFiler.Test` assembly run: 1312/1312 passed under a coverage-enabled
`vstest.console.exe` run. Full toolchain (CSharpier format/check, analyzer rebuild, nullable
rebuild) passed in a single pass with no failures.
Loading
Loading