Skip to content

Bug: breadcrumb-selectrow-emits-rooted-path-leaving-d1-half-closed #637

Description

@drmoisan
  • Work Mode: full-bug

Summary

Issue #614 established the invariant that SelectedFolderPath is an archive-relative stem, and
created ArchiveStemContract to express it. The invariant is enforced at the filing boundary, where
EmailFilerConfig.ResolvePaths calls RequireArchiveRelativeStem, but it is not enforced at the
producer. BreadcrumbBridgeRouter.SelectRow still commits a rooted filing target verbatim when that
target is at or under the bound archive root, so a rooted value can still become
SelectedFolderPath. That is defect D1 half-closed: the store-root and cross-store leaks are
stopped, but rootedness as such still escapes the producer.

Two things make this worth fixing rather than tolerating.

First, it left a live trap that has already fired once. During #614 remediation cycle 1 the OK-path
guard was widened to accept rooted under-root values so that it would agree with SelectRow. Because
nothing between the guard and the filing boundary normalizes the value, the accepted value reached
RequireArchiveRelativeStem and threw. ButtonOK_Click is async void and rethrows, and
ExecuteMovesAsync wraps its core in try/finally with no catch, so the ArgumentException became an
unhandled UI-thread exception after the form had already been hidden. The re-audit caught it and the
change was reverted. The underlying asymmetry that made the widening look reasonable is still
present.

Second, the D8 normalizer is only half-wired. EfcDataModel.ToArchiveRelativeStem exists and is
correct, but it is called only from the MAPIFolder overload of MoveToFolderAsync. The string
overload assigns DestinationOlStem = folderpath verbatim, so it performs no normalization at all.
Any rooted value arriving through that overload depends entirely on the boundary throw.

The fix is to normalize at the producer: in SelectRow, when TryMakeArchiveRelative succeeds with
a non-empty stem, commit the stem rather than the rooted input; when it succeeds with an empty stem
the value is the archive root itself, which SelectHierarchyPath already treats as a deterministic
non-selection and SelectRow should too. Once the producer cannot emit a rooted value, the OK guard
and the filing boundary agree by construction rather than by coincidence, and the composition test
added during remediation keeps them agreeing.

This also requires updating the existing test that asserts a rooted input survives selection, so that
it asserts the stem instead. That is a deliberate spec correction of the same kind #614 already
applied twice, and should be recorded as such rather than treated as a weakened test.

Environment

Steps to Reproduce

  1. Bind breadcrumb rows with an archive root, and present a suggestion row whose filing target is a
    rooted path at or under that root. FolderPredictor.ProjectSuggestionPath strips the archive
    prefix only when the suggestion is strictly under it, so a suggestion whose folder is the archive
    root is returned rooted and verbatim.
  2. Select that row. BreadcrumbBridgeRouter.SelectRow commits the rooted value to
    SelectedFolderPath.
  3. Observe that the value reaching the filing boundary is rooted, and is rejected there by
    RequireArchiveRelativeStem rather than having been normalized at the producer.

Expected Behavior

SelectedFolderPath is always an archive-relative stem. The producer normalizes; the boundary guard
is a backstop that never fires in normal operation. A row whose filing target is the archive root
itself is a non-selection, consistently with SelectHierarchyPath.

Actual Behavior

SelectRow commits a rooted value verbatim. The invariant is enforced only at the boundary, where
violating it is an exception rather than a corrected value.

Logs / Screenshots

  • Attached minimal logs or screenshot
  • Snippet: not applicable; established by source tracing. See BreadcrumbBridgeRouter.SelectRow, the
    string overload of EfcDataModel.MoveToFolderAsync, and
    ArchiveStemContract.RequireArchiveRelativeStem.

Impact / Severity

  • Blocker
  • High
  • Medium
  • Low

No user-visible defect on the shipped code: a rooted selection is rejected at the OK guard with a
clear dialog. Severity is Medium because the asymmetry is a live trap for future changes, as
demonstrated by remediation cycle 1, and because the half-wired D8 normalizer means one filing
overload relies entirely on a throw.

Source

From: docs/features/potential/2026-08-26-breadcrumb-selectrow-emits-rooted-path-leaving-d1-half-closed.md

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions