Skip to content

fix(440): let repeated Left walk the Qfc breadcrumb chain to the root - #689

Merged
drmoisan merged 6 commits into
mainfrom
bug/breadcrumb-left-right-arrow-parent-child-navigation-440
Aug 29, 2026
Merged

fix(440): let repeated Left walk the Qfc breadcrumb chain to the root#689
drmoisan merged 6 commits into
mainfrom
bug/breadcrumb-left-right-arrow-parent-child-navigation-440

Conversation

@drmoisan

Copy link
Copy Markdown
Owner

fix(440): let repeated Left walk the Qfc breadcrumb chain to the root

Summary

  • Removes a single conjunct from the LeftArrow() transition guard in BreadcrumbStateModel, so repeated Left presses walk the breadcrumb ancestor chain all the way to the root instead of stopping after one level.
  • Aligns the Qfc surface with the Efc surface, where BreadcrumbBridgeRouter.Arrows.cs already walked to the root.
  • Adds two MSTest regression tests with recorded fail-before / pass-after evidence, and corrects two existing tests that encoded the defective one-step contract.
  • Touches exactly three repository source files: one production file and two test files. No new test file and no project-file edit.
  • Full C# toolchain passes in a single clean sequence with zero errors; repository-wide coverage moves up slightly on both line and branch.

Why

BreadcrumbStateModel.LeftArrow() gated its parent-select on activeIndex.Value == row.Chain.Count - 1, which is true only while the active segment is the leaf. After the first Left press the active index is no longer the leaf, so the guard failed and every subsequent press fell through as unhandled. The user-visible effect was that Left could ascend exactly one level of a breadcrumb chain and then stopped.

The clause is unnecessary for safety. BreadcrumbStateRow.ActivateSegment(int) already refuses a negative index, so the root boundary and the pre-existing unhandled fall-through are preserved without it.

Most of the original issue #440 statement already landed on main as a secondary payload of feature #498. The residual defect addressed here is Qfc-only, and the narrowed scope is recorded in the feature spec.

What Changed

Core fix

  • UtilitiesCS/OutlookObjects/Folder/BreadcrumbStateModel.cs — deleted the activeIndex.Value == row.Chain.Count - 1 conjunct from the LeftArrow() transition guard. The _selectedSubfolderIndex < 0 conjunct and the row.ActivateSegment(activeIndex.Value - 1) call are retained unchanged. The adjacent #440 comment was rewritten to describe a walk rather than a single leaf-anchored step. No other conditional in the file was altered; in particular TryRightTreeTransition is untouched.

Tests

  • UtilitiesCS.Test/OutlookObjects/Folder/BreadcrumbStateModelSequenceTests.cs — added LeftArrow_RepeatedOnThreeSegmentChain_WalksToRootThenReportsUnhandled, which asserts the active segment index after every press (2 to 1 to 0, then unhandled at 0), and LeftArrow_WalkFromAnOpenLeafExpansion_ClearsTheExpansionAndStillReachesTheRoot, which covers the open-leaf-expansion edge case. Corrected Arrows_RightExpandsThenLeftCollapses_UnhandledWhenNothingChanges to the walk contract by extending the sequence to the root.
  • UtilitiesCS.Test/OutlookObjects/Folder/FolderBreadcrumbBridgeRouterTests.cs — corrected Route_LeftArrow_NothingToCollapse_ReportsUnhandledLeft in place so it drives the chain to the root before asserting the unhandled Left, and replaced the superseded one-step-limit comment. Net line-negative.

Docs

Architecture / How It Fits Together

Arrow keys reach the breadcrumb state machine through two surfaces. The Qfc surface routes through FolderBreadcrumbBridgeRouter into BreadcrumbStateModel, which owns the selection and expansion state. The Efc surface routes through QuickFiler/Controllers/BreadcrumbBridgeRouter.Arrows.cs.

LeftArrow() attempts a tree transition first and falls through to the pre-existing collapse behavior when no parent-select is available. The root boundary is enforced one level down, inside BreadcrumbStateRow.ActivateSegment(int), which refuses a plain row, a negative index, an index at or beyond Chain.Count - 1, and a no-change index. Removing the leaf-anchored conjunct therefore changes only which presses reach ActivateSegment; it does not widen what ActivateSegment will accept.

Only the second and subsequent Left presses change behavior. ActiveSegmentIndex defaults to Chain.Count - 1, so a freshly selected row is leaf-anchored and the first press behaves identically before and after.

Verification

Completed

  • dotnet tool run csharpier format on the three owned paths, then dotnet tool run csharpier check . — exit 0, Checked 1560 files, equal to the pre-change baseline.
  • msbuild TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:EnableNETAnalyzers=true /p:EnforceCodeStyleInBuild=true — exit 0, 0 errors, 5 warnings (unchanged from baseline).
  • msbuild TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:TreatWarningsAsErrors=true — exit 0, 0 errors, 5 warnings.
  • Both msbuild gates were shown to be non-vacuous: 0 occurrences of Skipping target "CoreCompile" and 40 occurrences of (Rebuild target(s)) in each file-logger output.
  • Full MSTest suite with coverage via the repository wrapper — baseline 6857/6857 passed, final 6859/6859 passed, no failures on either side. The increase of two is exactly the two added tests.
  • Fail-before / pass-after: the two new tests exit 1 against the pre-fix tree and exit 0 after the fix, both recorded as evidence artifacts.
  • Repository-wide coverage: line 85.2935% to 85.3026%, branch 79.2523% to 79.2558%. Per-file uncovered counts for the changed production file held at 2 lines and 3 branches, and all 19 instrumented lines in the post-change LeftArrow() span are covered.
  • Feature review produced policy-audit, code-review, and feature-audit artifacts, all three PASS, with zero blocking findings.

The five analyzer and nullable warnings are the pre-existing System.Reactive 7.0.0 packages-config advisory, one from each of QuickFiler, TaskMaster, ToDoModel, UtilitiesCS, and UtilitiesCS.Test. They are unchanged from the baseline measured before this work began.

Recommended

  • Exercise Left repeatedly on a deep breadcrumb chain in the Qfc folder drop-down and confirm it ascends to the root and then leaves the drop-down close behavior intact.
  • Confirm Right on a childless node still reaches the Pop Out / Enumerate Conversation dialog by keyboard.

Backward Compatibility / Migration Notes

No public API change, no renamed path, no removal. The change is a relaxation of one internal guard condition. Behavior at the root boundary is unchanged: Left at the root still returns false and still emits an unhandled Left arrow, so the legacy fall-through that closes the folder drop-down is retained.

Risks and Mitigations

  • Risk: a consumer relied on Left stopping after one level. Mitigation: the Efc surface already walked to the root, so the two surfaces were inconsistent and the Qfc behavior was the outlier. Both breadcrumb suites were re-run green.
  • Risk: the relaxed guard permits an out-of-range parent-select. Mitigation: ActivateSegment independently rejects a negative index; a dedicated test asserts the third press returns false with the index still 0.
  • Rollback: restoring the single deleted conjunct reverts the behavior change; the two added tests would then fail, which is the intended signal.

Review Guide

  1. UtilitiesCS/OutlookObjects/Folder/BreadcrumbStateModel.cs — the whole functional change is one deleted line plus a comment rewrite.
  2. BreadcrumbStateModelSequenceTests.cs — the two new tests and the corrected sequence test.
  3. FolderBreadcrumbBridgeRouterTests.cs — a mechanical replacement of two inline four-line calls with the existing single-line helper, plus the extra Arrange press.
  4. The feature folder is documentation and evidence only.

Follow-ups

  • The repository-wide analyzer version skew is pre-existing and untouched here: the packages-config files pin Meziantou.Analyzer 3.0.174 and Roslynator.Analyzers 4.16.1 while the hand-written Analyzer items name 3.0.156 and 4.16.0. A fresh worktree fails every msbuild invocation with CS0006 until the missing package directories are provisioned. The durable realignment belongs to its own issue.
  • The corrected router test Route_LeftArrow_NothingToCollapse_ReportsUnhandledLeft is defect-neutral rather than defect-detecting: its two Arrange presses discard their results, so it passes both before and after the fix. The walk contract is pinned at state-machine level by the two new tests, which do carry fail-before evidence. Worth tightening separately.
  • Two divergences recorded in the spec as explicit non-goals remain open: the Right-descent commit asymmetry between the Qfc and Efc surfaces, and the single-level Right descent limit present on both.

GitHub Auto-close

drmoisan and others added 6 commits August 29, 2026 02:44
Preparation-mode orchestration for issue #440. Adds the active feature folder with research, spec, and an atomic plan cleared through five preflight rounds.

Research established that most of issue #440 already landed on main as a secondary payload of feature 498. The residual defect is Qfc-only: BreadcrumbStateModel.LeftArrow gates its parent-select transition on a leaf-anchored conjunct, so Left walks up exactly one level while the Efc surface already walks to the root. Scope is one production file plus two existing test files.

No production or test source file is modified by this commit.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Persists three agent-memory entries written during the issue #440 preparation run, plus their index lines.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Removes the leaf-anchored conjunct `activeIndex.Value == row.Chain.Count - 1`
from the LeftArrow() transition guard in
UtilitiesCS/OutlookObjects/Folder/BreadcrumbStateModel.cs. That single clause was
the whole of the residual #440 defect: it held only while the active segment was
still the leaf, so Left performed the parent-select exactly once and every later
press fell through to TryCollapseLeaf(), which reported an unhandled arrow and
let the legacy handler dismiss the QuickFiler folder drop-down.

The remaining guard reads: no subfolder selected, an active segment index
exists, and ActivateSegment(activeIndex.Value - 1) succeeds. The root boundary
is now enforced by BreadcrumbStateRow.ActivateSegment, which already refuses a
negative index, so Left at the root still returns false and the pre-existing
fall-through is preserved unchanged. The _selectedSubfolderIndex < 0 conjunct is
retained, so Left with a subfolder highlighted still resets that selection. The
adjacent #440 comment is rewritten to describe the walk rather than a single
leaf-anchored step.

Two landed tests encoded the one-step limit and are corrected:

- Arrows_RightExpandsThenLeftCollapses_UnhandledWhenNothingChanges in
  UtilitiesCS.Test/OutlookObjects/Folder/BreadcrumbStateModelSequenceTests.cs is
  extended to the root before asserting the unhandled press, per decision D1.
- Route_LeftArrow_NothingToCollapse_ReportsUnhandledLeft in
  UtilitiesCS.Test/OutlookObjects/Folder/FolderBreadcrumbBridgeRouterTests.cs is
  corrected in place, reusing the file's ArrowAsync helper so the change is net
  line-negative against the 500-line limit.

Two new tests cover the walk and the open-leaf-expansion edge case, asserting
the active segment index after every press. Both were red before the fix and
green after.

The Efc surface is untouched; it already satisfied the contract. Full suite
6859/6859 green, up from a 6857 baseline by exactly the two added tests.

Refs #440

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BmFjm2aSpooVerwWWWuN8S
Records the policy-audit, code-review, and feature-audit produced for the
issue #440 breadcrumb left-arrow walk-to-root fix. All three verdicts are
PASS with zero blocking findings, so no remediation cycle was opened.

The reviewer re-derived the coverage figures independently rather than
accepting the executor's report, and re-ran the affected Qfc and Efc
breadcrumb suites.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BmFjm2aSpooVerwWWWuN8S
Captures two entries written while delivering the breadcrumb left-arrow
walk-to-root fix: the executor's note that estimated evidence timestamp
labels can drift ahead of real write times, and the reviewer's residual
findings for this branch.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BmFjm2aSpooVerwWWWuN8S
…dex)

# Conflicts:
#	.claude/agent-memory/atomic-planner/MEMORY.md
@drmoisan
drmoisan merged commit ecdb1c8 into main Aug 29, 2026
9 of 10 checks passed
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.

Bug: breadcrumb-left-right-arrow-parent-child-navigation

1 participant