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
33 changes: 32 additions & 1 deletion QuickFiler.Test/Controllers/KaStringAsyncTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,13 +89,44 @@ public void KeyEquals_ContainsMatchWhileActivated_InvokesUpdateAndReturnsTrue()
result.Should().BeTrue("a substring match returns true");
updateArg
.Should()
.Be("b", "Update receives Key.Substring(other.Length - 1, 1) => index 1 => \"b\"");
.Be(
"b",
"Update receives the last character of the matched span (Key.IndexOf(\"ab\", StringComparison.Ordinal) + other.Length - 1 = 1) => \"b\""
);
ka.Activated.Should()
.BeTrue(
"the contains-match branch returns before the trailing Activated = false reset"
);
}

[TestMethod]
public void KeyEquals_ContainsMatchAtNonPrefixIndex_InvokesUpdateWithLastMatchedCharacter()
{
// Intent: issue #583 regression. Branch 1's Update argument was computed as
// Key.Substring(other.Length - 1, 1), which is only correct when other is a prefix
// of Key. For Key="01" and other="1", the probe matches at index 1, not index 0.
// Before the fix this yielded "0"; after the fix it yields "1".

// Arrange
string updateArg = null;
var ka = NewKa("01", update: s => updateArg = s);
ka.Activated = true;

// Act
var result = ka.KeyEquals("1");

// Assert
result.Should().BeTrue("a substring match returns true");
updateArg
.Should()
.Be(
"1",
"Update receives the last character of the matched span (Key.IndexOf(\"1\", "
+ "StringComparison.Ordinal) + other.Length - 1 = 1), not the pre-fix "
+ "prefix-only offset that yielded \"0\""
);
}

[TestMethod]
public void KeyEquals_ContainsMatchWhileNotActivated_ReturnsTrueWithoutUpdate()
{
Expand Down
13 changes: 10 additions & 3 deletions QuickFiler/Controllers/KaStringAsync.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,10 @@ public bool Activated
/// </para>
/// <para>
/// <b>Argument contract.</b> <paramref name="other"/> must be non-null and non-empty. The
/// guard clause at the top of this method rejects both fail-fast, so branch 1's substring
/// offset expression is never evaluated with a negative start index.
/// guard clause at the top of this method rejects both fail-fast, so branch 1's derived
/// offset (Key.IndexOf(other) plus the matched length) is never evaluated with a
/// negative start index: IndexOf is non-negative because branch 1 only runs when
/// Contains already matched, and other.Length is at least 1 because of the guard above.
/// </para>
/// <para>
/// <b>Consequence for callers.</b> <c>KbdActions</c> methods whose key type is
Expand Down Expand Up @@ -125,7 +127,12 @@ public bool KeyEquals(string other)
if (Key.Contains(other))
{
if (Activated && Update is not null)
Update(Key.Substring(other.Length - 1, 1));
Update(
Key.Substring(
Key.IndexOf(other, StringComparison.Ordinal) + other.Length - 1,
1
)
);
return true;
}
else if (other.Length == 1)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
# Coverage Baseline (P0-T8)

- Timestamp: 2026-09-13T01-00
- Command: <resolved dotnet-coverage executable> collect --output <session-temp-file>
--output-format cobertura --settings <dotnet-coverage module-exclude settings file> --
<resolved vstest executable> QuickFiler.Test\bin\Debug\QuickFiler.Test.dll /InIsolation
/Settings:scripts\vscode\TaskMaster.cli.runsettings
"/TestCaseFilter:TestCategory!=LiveOutlook"
- EXIT_CODE: 0

## Deviation note — dotnet-coverage module-exclude settings

The first attempt at this capture, using only the TaskMaster CLI runsettings file with no
dotnet-coverage module excludes, failed 3 of 1393 tests
(InitEmailQueue_ZeroBatchSize_ReturnsEmptyListWithoutThrowing,
InitEmailQueue_ZeroBatchSize_StillStartsBackgroundWorker,
InitEmailQueue_PositiveBatchSize_RetainsExistingProjectionAndFrameDrop) with a
System.TypeInitializationException on Deedle.Reflection / netstandard, Version=2.1.0.0. This is
a known, pre-existing, environment-level failure mode of dotnet-coverage's own instrumentation
against Deedle/F# assemblies, unrelated to KaStringAsync and unrelated to this branch's diff
(confirmed no source diff from origin/main at the time of this capture). The repository's own
TaskMaster.runsettings already carries a matching Deedle/FSharp module-exclude block for the
built-in Code Coverage collector; dotnet-coverage's own instrumentation does not read that file,
so an equivalent exclude was supplied to dotnet-coverage collect via its own --settings file
(ModulePaths/Exclude for .*Deedle.*, .*FSharp.*, .*Castle\.Core.*, .*FluentAssertions.*,
.*Moq.*, .*Microsoft\.Testing.*, .*MSTest.*), written to a temp-directory file, never added to
the repository. With that settings file supplied, the same capture reported "Test Run
Successful.", 1393/1393 Passed.

## Test run result

```
Test Run Successful.
Total tests: 1393
Passed: 1393
Total time: 15.6062 Seconds
```

## Root coverage figures

- Root line-rate: 0.4298999577286177
- Root branch-rate: 0.24095967959333

## KaStringAsync.cs covered/total

- Covered: 60
- Total: 60

## Per-line hits projection

| Line | Hits |
|---|---|
| 12 | 1 |
| 14 | 1 |
| 15 | 1 |
| 16 | 1 |
| 17 | 1 |
| 18 | 1 |
| 19 | 1 |
| 20 | 1 |
| 21 | 1 |
| 22 | 1 |
| 23 | 1 |
| 24 | 1 |
| 25 | 1 |
| 26 | 1 |
| 27 | 1 |
| 32 | 1 |
| 33 | 1 |
| 39 | 1 |
| 40 | 1 |
| 46 | 1 |
| 47 | 1 |
| 50 | 1 |
| 53 | 1 |
| 54 | 1 |
| 107 | 1 |
| 110 | 1 |
| 111 | 1 |
| 112 | 1 |
| 115 | 1 |
| 116 | 1 |
| 117 | 1 |
| 118 | 1 |
| 119 | 1 |
| 120 | 1 |
| 121 | 1 |
| 122 | 1 |
| 125 | 1 |
| 126 | 1 |
| 127 | 1 |
| 128 | 1 |
| 129 | 1 |
| 131 | 1 |
| 132 | 1 |
| 133 | 1 |
| 134 | 1 |
| 135 | 1 |
| 136 | 1 |
| 137 | 1 |
| 138 | 1 |
| 139 | 1 |
| 140 | 1 |
| 141 | 1 |
| 142 | 1 |
| 143 | 1 |
| 144 | 1 |
| 145 | 1 |
| 150 | 1 |
| 151 | 1 |
| 157 | 1 |
| 158 | 1 |

## Raw output disposition

- Raw-output location (relative to the per-user temp directory root): p583-p0t8b/coverage.cobertura.xml
- Prefix comparison (raw-output full path begins with repository root full path): False
- Post-deletion existence check of the raw file: False (absent)
- Directory listing of evidence/baseline/ after deletion (entry names only):
- coverage-tool-probe.md
- csharpier-check.md
- dotnet-bootstrap.md
- msbuild-analyzers.md
- msbuild-nullable.md
- nuget-restore.md
- phase0-instructions-read.md

## Output Summary

Exit code 0; inner test run "Test Run Successful." with 0 Failed (1393/1393 Passed, after
supplying a dotnet-coverage module-exclude settings file to work around a known pre-existing
Deedle/FSharp instrumentation crash unrelated to this change); root line-rate
0.4298999577286177, root branch-rate 0.24095967959333; KaStringAsync.cs covered/total 60/60;
per-line hits projection holds 60 rows, no repeated line number; raw output confirmed outside
the repository root and deleted; evidence/baseline/ directory listing contains no .xml entry.
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Coverage Tool Probe

- Timestamp: 2026-09-13T00-15
- Command: Get-Command dotnet-coverage(.exe), then its version switch
- EXIT_CODE: 0

## Result

- Present: yes (already installed as a global dotnet tool; no install step was needed)
- Resolved path: <user-profile>\.dotnet\tools\dotnet-coverage.exe
- Version string: 18.10.0+f4cc39224845ffa74bf246c9da2399d50e5d6342

## Output Summary

dotnet-coverage is present as a global tool, resolved path recorded above, version string
18.10.0, observed exit code 0 for the version-switch invocation, matching the recorded shape at
docs/features/archive/2026-08-07-quickfiler-keyboard-action-contract-defects-445/evidence/baseline/coverage-tool-probe.2026-08-22T09-32.md.
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# CSharpier Check (Baseline)

- Timestamp: 2026-09-13T00-20
- Command: <resolved dotnet executable> tool run csharpier check . (run from repository root,
read-only)
- EXIT_CODE: 0

## Verbatim output

```
Checked 1624 files in 5999ms.
```

## Output Summary

Files-checked count: 1624. Files-needing-formatting count: 0 (no per-file line appeared ahead
of the summary line). Exit code 0, matching the recorded clean-tree shape ("Checked 1517 files
in 6621ms.", exit code 0) at
docs/features/archive/2026-08-07-quickfiler-keyboard-action-contract-defects-445/evidence/baseline/csharpier-check.2026-08-22T09-19.md;
the higher file count here reflects the larger repository tree at this later point in time.
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Dotnet Bootstrap

- Timestamp: 2026-09-13T00-05

## Step 1 — SDK resolution

The per-worktree .dotnet-sdk junction did not resolve (Test-Path returned False before this
task ran). Fallback provisioner scripts/vscode/Install-RepoDotNetSdk.ps1 was run.

- Command: pwsh -NoProfile -File scripts/vscode/Install-RepoDotNetSdk.ps1
- Output: "Downloading .NET SDK 8.0.205 from
https://builds.dotnet.microsoft.com/dotnet/Sdk/8.0.205/dotnet-sdk-8.0.205-win-x64.zip...",
"Installed repo-local .NET SDK 8.0.205 to
<repo-root>\.dotnet-sdk."
- Resolved dotnet executable: .dotnet-sdk/dotnet.exe (repo-relative), version switch confirms
8.0.205.
- EXIT_CODE: 0

## Step 2 — Tool restore

- Command: <resolved dotnet executable> tool restore (run from repository root)
- EXIT_CODE: 0
- Output: "Tool 'csharpier' (version '1.2.6') was restored. Available commands: csharpier" /
"Restore was successful." — matches the recorded success shape at
docs/features/archive/2026-08-07-quickfiler-keyboard-action-contract-defects-445/evidence/baseline/dotnet-tool-restore.2026-08-22T09-18.md.

## Output Summary

Both steps succeeded: repo-local .NET SDK 8.0.205 installed for this worktree; CSharpier 1.2.6
restored via dotnet-tools.json manifest, exit code 0, matching the archived precedent's success
text verbatim.
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# KbdActionsTests Baseline (P0-T9)

- Timestamp: 2026-09-13T01-05
- Command: <resolved vstest executable> QuickFiler.Test\bin\Debug\QuickFiler.Test.dll
/InIsolation /Settings:scripts\vscode\TaskMaster.cli.runsettings
"/TestCaseFilter:FullyQualifiedName~KbdActionsTests"
- EXIT_CODE: 0

## Verbatim result

```
Test Run Successful.
Total tests: 4
Passed: 4
Total time: 1.2679 Seconds
```

## Per-class reporting

| Class | Total | Passed | Failed | Exit |
|---|---|---|---|---|
| KbdActionsTests | 4 | 4 | 0 | 0 |

Individual tests: Add_WhenSourceAndStoredKeysAreDistinct_DoesNotTreatSubstringAsDuplicate,
Add_WhenSourceAndStoredKeyAreExactDuplicate_ThrowsArgumentException,
EnumerableConstructor_WhenStoredKeysDifferButKeyEqualsOverlaps_DoesNotThrow,
FilterKeys_WhenDistinctStoredKeysCoexist_PreservesKeyboardMatchingSemantics (the pinned test).

## Output Summary

Exit code 0; verdict "Test Run Successful."; 4 Passed, 0 Failed for the KbdActionsTests class,
including the pinned test FilterKeys_WhenDistinctStoredKeysCoexist_PreservesKeyboardMatchingSemantics.
This baseline count (4) is expected to differ from the archived precedent's count of 3 on
2026-08-22 (docs/features/archive/2026-08-07-quickfiler-keyboard-action-contract-defects-445/evidence/baseline/vstest-baseline.2026-08-22T09-18.md),
because one test method (Add_WhenSourceAndStoredKeyAreExactDuplicate_ThrowsArgumentException or
a sibling) has been added to the pinned file since that baseline was recorded; per the plan's
own acceptance text this task's count is not compared against that archived figure. No file was
diffed to obtain this result; it is derived solely from the test-run outcome.
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# MSBuild Analyzer Rebuild (Baseline)

- Timestamp: 2026-09-13T00-30
- Command: MSBuild.exe (VS18) TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug
"/p:Platform=Any CPU" /p:EnableNETAnalyzers=true /p:EnforceCodeStyleInBuild=true
/flp:logfile=<detailed-file-log>;verbosity=detailed
- EXIT_CODE: 0

## Verdict line

```
Build succeeded.
0 Warning(s)
0 Error(s)
```

## Log-line counts (from the detailed file logger)

- "Skipping target ... CoreCompile" occurrences: 0
- "CoreCompile:" occurrences: 130 (proves the rebuild was not vacuous)
- Total warning count: 0 (console verdict "0 Warning(s)"; no analyzer/compiler warning lines
present in the detailed log for this run — the five System.Reactive
PackagesConfigCheck.targets target-invocation trace lines present in the log are target-graph
trace lines, not warning diagnostics, and none is followed by a warning-severity message text)

## Output Summary

Exit code 0; verdict "Build succeeded."; 0 "Skipping target CoreCompile" occurrences; 130
"CoreCompile:" occurrences (non-vacuous rebuild); recorded warning count is 0, which is the
ceiling P5-T3 compares against. This differs numerically from the archived precedent's 5
System.Reactive packages.config warnings at
docs/features/archive/2026-08-07-quickfiler-keyboard-action-contract-defects-445/evidence/baseline/msbuild-analyzers.2026-08-22T09-21.md,
but is consistent in kind (0 skip / >=9 CoreCompile / 0 errors); the numeric warning count is
recorded as observed rather than assumed to match the archived figure.
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# MSBuild Nullable Rebuild (Baseline)

- Timestamp: 2026-09-13T00-35
- Command: MSBuild.exe (VS18) TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug
"/p:Platform=Any CPU" /p:TreatWarningsAsErrors=true
/flp:logfile=<detailed-file-log>;verbosity=detailed
- EXIT_CODE: 0

## Verdict line

```
Build succeeded.
0 Warning(s)
0 Error(s)
```

## Log-line count

- "Skipping target ... CoreCompile" occurrences: 0

## Output Summary

Exit code 0; verdict "Build succeeded."; "Skipping target CoreCompile" count of exactly 0
(141 "CoreCompile:" occurrences, confirming the rebuild was not vacuous). Matches the recorded
shape (0 skip / 0 errors) at
docs/features/archive/2026-08-07-quickfiler-keyboard-action-contract-defects-445/evidence/baseline/msbuild-nullable.2026-08-22T09-23.md.
No nullable opt-in property (Nullable=enable) was passed, per the Command Reference.
Loading
Loading