Fix KaStringAsync.KeyEquals branch-1 offset arithmetic for non-prefix Contains matches - #874
Merged
Merged
Conversation
…rage figure Per the projection-only evidence decision recorded on issue 671 on 2026-09-11, no new raw Cobertura XML and no new TRX file may be added to git. The approved plan wrote two raw coverage documents as committed evidence: coverage-baseline.cobertura.xml under evidence/baseline and coverage-postchange.cobertura.xml under evidence/qa-gates. Both are removed. P0-T8 and P5-T5 still run dotnet-coverage, but the Cobertura output now lands in a session folder beneath the per-user temporary directory, outside the repository, and is read then deleted rather than committed. Each task records a prefix comparison proving the location is outside the repository root, a post-deletion existence check, and a directory listing free of any xml entry. Every numeric figure is preserved. coverage-baseline.md and coverage-postchange.md now carry the root line-rate, the root branch-rate, the per-file covered and total counts, and a new per-line hits projection. P5-T7 computes the delta from those two markdown artifacts alone, naming no raw document, and still reports baseline, post-change and changed-line percentages. P5-T7 also gained a stated denominator and a non-empty-denominator floor, so the changed-line percentage is mechanically determinate and its quantifier can fail. P5-T15 and the git-diff-anchoring reference were corrected out of footprint, because the scope list omitted issue.md and the research record, which the anchored diff necessarily reports, leaving the terminal gate ordering an unbounded phase restart. Preflight cleared at round 13. Task count and numbering unchanged at 30.
…ence under coordinator quota hold Committed by the parallel-orchestrator coordinator under a full hold: the active account reaches its 5-hour cap within minutes and the fallback account is also exhausted until 06:00Z, so every running child would otherwise die mid-task with this work uncommitted and unrecoverable. Working state, not a completion claim. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…redact host paths Final QC loop passed in a single clean pass (csharpier check, analyzer rebuild, nullable rebuild, coverage-instrumented MSTest run); coverage delta and final-QC attestation confirm no regression and 100% changed-line coverage on the KaStringAsync.cs fix. All six spec.md acceptance criteria are checked off. Also redacts two absolute host paths left in earlier baseline evidence (coverage-tool-probe.md, dotnet-bootstrap.md) per repository evidence-hygiene convention. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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.
Suggested title
Fix KaStringAsync.KeyEquals branch-1 offset arithmetic for non-prefix Contains matches
Summary
KaStringAsync.KeyEquals's Contains-guarded branch computed itsUpdatecallback argumentfrom prefix-only arithmetic (
Key.Substring(other.Length - 1, 1)), which only produces thecorrect matched character when
otheris a prefix ofKey.Key.Substring(Key.IndexOf(other, StringComparison.Ordinal) + other.Length - 1, 1).Containsguard itself is unchanged, per the binding maintainer decision recorded inissue.md; noStartsWithcall is introduced anywhere in the file.Key = "01",other = "1",now correctly yields
"1"instead of"0"); one pre-existing test's explanatory string isreworded (its asserted value is unchanged) because it quoted the replaced literal expression.
KaStringAsyncconstruction site passes a nullUpdatecallback, so the corrected branch has no observable effect on current behavior.MSTest run) passes in a single clean pass; changed-line coverage on the fix is 100%, with no
regression on any previously-covered line.
Why
Branch 1 of
KeyEqualsguards on a substring test (Key.Contains(other)) but computed itsUpdateargument using an offset derived only fromother's own length. That offset is onlycorrect when
otherhappens to be a prefix ofKey; for a substring match at any otherposition, the wrong character is passed to
Update. The maintainer decision recorded inissue.md(2026-09-11) required keeping theContainsguard as-is and correcting only theoffset arithmetic, deriving it from
Key.IndexOf(other)(the actual match position) instead.The research record backing this plan confirms the two search modes (
Contains, ordinal;IndexOf, comparison-dependent) cannot disagree for this method's actual ASCII-digit inputdomain, so an explicit
StringComparison.Ordinalargument on the addedIndexOfcall wasadded for textual consistency with the guard, not because any active gate requires it.
What Changed
Core fix
QuickFiler/Controllers/KaStringAsync.cs: corrected the branch-1Updateoffset expressionto derive from
Key.IndexOf(other, StringComparison.Ordinal); reworded one doc-commentsentence in the "Argument contract" paragraph to describe the new derivation instead of the
old prefix-only one.
Tests
QuickFiler.Test/Controllers/KaStringAsyncTests.cs: addedKeyEquals_ContainsMatchAtNonPrefixIndex_InvokesUpdateWithLastMatchedCharacter, covering thetwo-digit-width non-prefix regression case; reworded the because-string of the pre-existing
prefix-case test (asserted value
"b"unchanged) so it no longer quotes the replaced literalexpression.
Docs / feature folder / evidence
docs/features/active/kastringasync-keyequals-contains-offset-583/:issue.md,spec.md,the atomic plan, the research record, and 21 evidence artifacts under
evidence/baseline/,evidence/regression-testing/, andevidence/qa-gates/(baseline and post-change toolchaingate results, red-before-fix/green-after-fix regression-test captures, coverage delta, final
QC attestation, and the acceptance-criteria status summary). No raw coverage or test-results
file is included; all committed evidence is markdown projections per the repository's
evidence-hygiene convention.
Architecture / How It Fits Together
KaStringAsyncis a keyboard-action value object implementingIKbdAction<string, Func<string, Task>>.KeyEqualsis invoked byKbdActions' keyboard-filtering methods(
ContainsKey,FilterKeys,Find,FindIndex, the indexer) to test a keystroke probeagainst a registered key and, when a non-null
Updatecallback is present, to feed it thecharacter it should surface. The change is confined to the internal arithmetic of one branch
of one method; the public signature, return contract, and every other branch (the single-char
non-match branch and the multi-character non-match branch) are unchanged.
Verification
Completed (see the linked evidence artifacts for full command/output detail):
/p:EnableNETAnalyzers=true /p:EnforceCodeStyleInBuild=true): Buildsucceeded, 0 errors, 0 skip-CoreCompile, both baseline and post-change.
/p:TreatWarningsAsErrors=true): Build succeeded, 0 errors, 0skip-CoreCompile, both baseline and post-change.
"0"against expected"1".KaStringAsyncTestsPassed.KaStringAsync.cscovered/total 65/65 post-change (60/60 baseline); changed-line coverage onthe fix is 6/6 = 100%; no previously-covered line regressed.
QuickFiler.Test/Controllers/KbdActionsTests.cs,FilterKeys_WhenDistinctStoredKeysCoexist_PreservesKeyboardMatchingSemantics): 4/4 Passedboth before and after the fix, 0 delta; that file is untouched by this change.
rebuild, nullable rebuild, coverage capture, KbdActions run, coverage-delta computation)
recorded exit code 0 (CSharpier format's measured rewrite count is 0), and the anchored
diff/status check confirms every changed path falls within this change's declared write set.
spec.md(AC1-AC6); seeevidence/qa-gates/ac-status-summary.md.Recommended: none beyond the completed toolchain run above; no manual verification step
applies, because the defect has no observable effect in current production behavior (every
production construction path leaves
Updatenull).Backward Compatibility / Migration Notes
None.
KeyEquals's public signature, return contract, and exception contract are allunchanged. The corrected
Updateargument value differs from today's value only for matchpositions that no current production construction path exercises (
Updateis always null inproduction today), so there is no observable behavior change for any existing caller.
Risks and Mitigations
Updatecallback into a productionKaStringAsyncconstruction site, newly exercising this corrected branch.Mitigation: the corrected behavior is now covered by a regression test and the doc
comment describes the new derivation;
spec.md's Rollout & Follow-up section flags this asthe one condition under which the corrected path should be re-verified.
discovered; the change is not behind a feature flag and requires no migration.
Review Guide
Suggested order:
QuickFiler/Controllers/KaStringAsync.cs— the one-line arithmetic fix and its doc-commentreword.
QuickFiler.Test/Controllers/KaStringAsyncTests.cs— the new regression test and thebecause-string reword.
docs/features/active/kastringasync-keyequals-contains-offset-583/spec.md— acceptancecriteria and design rationale.
evidence/subtree — toolchain gate and coverage-delta artifacts, useful for confirmingthe verification claims above without re-running the toolchain locally.
The 24 markdown files are feature-folder documentation and evidence; none of them requires the
same scrutiny as the two source files.
Follow-ups
KaStringAsyncconstructionsite a non-null
Updatecallback, that change should re-verify this corrected offsetbehavior against the newly reachable code path (see
spec.md's Rollout & Follow-up section).GitHub Auto-close
not be verified; issue KaStringAsync.KeyEquals branch 1 computes a prefix-only Substring offset under a Contains guard #583 is the subject of this change but is not asserted here as a
verified auto-close target.)