Skip to content

[CmdPal] Time-decayed frecency signal for main-page ranking#49190

Draft
michaeljolley wants to merge 1 commit into
dev/mjolley/cmdpal-search-overhaulfrom
dev/mjolley/frecency-redesign
Draft

[CmdPal] Time-decayed frecency signal for main-page ranking#49190
michaeljolley wants to merge 1 commit into
dev/mjolley/cmdpal-search-overhaulfrom
dev/mjolley/frecency-redesign

Conversation

@michaeljolley

Copy link
Copy Markdown
Contributor

Phase 2 of the CmdPal search overhaul (stacked)

Base branch is dev/mjolley/cmdpal-search-overhaul (phase 1), NOT main. Phase 3 (provider weighting) will stack on this branch.

What changed

Replaces the list-position frecency heuristic in RecentCommandsManager with a real time-decayed signal so recently- and frequently-used commands reorder correctly within their ranker tier. The tier always dominates; frecency only reorders within a tier, so overall ordering behavior is preserved.

  • Time-decay weight: recency = 2^(-ageDays / halfLife) combined with log2(uses + 1) for frequency, clamped to the previous ~0..70 range so the ranker's within-tier math and FrecencyScale = 1.0 are unaffected.
  • HistoryItem.LastUsed: new persisted DateTimeOffset driving the decay.
  • Store cap grown from 50 to 500 entries (frecency decays gracefully, so a larger store is cheap and improves recall of older-but-frequent commands).
  • Legacy migration: persisted items without LastUsed deserialize as MinValue and are treated as used one day ago, so day-one behavior degrades to Uses-ordering rather than all-equal.
  • Serialization fix: the internal History property was never emitted by the source-generated serializer, so recent-command history was silently not persisted across restarts. Marked it [JsonInclude] so history (and the new LastUsed) actually round-trips. Old empty persisted state still deserializes cleanly.
  • Test seams: internal WithHistoryItem(commandId, now) / GetCommandHistoryWeight(commandId, now) overloads let tests inject strictly-increasing timestamps. Public overloads pass DateTimeOffset.UtcNow; the public IRecentCommandsManager contract is unchanged, so MainListPage needed no changes.

Design constants

  • Half-life: 3 days
  • Base weight: 10, frequency weight: 10, max weight: 70
  • Store cap: 500
  • Legacy backdate: 1 day

Tests

  • Rewrote the position-bucket tests as explicit time-decay tests (recency decay, frequency weighting, cap, legacy migration, serialization round-trip).
  • Kept the tier-invariant tests unchanged in spirit (tier still dominates; frecency only reorders within a tier).
  • Build: x64 Debug, exit 0.
  • Microsoft.CmdPal.UI.ViewModels.UnitTests: 150/150 pass (RecentCommandsTests 14/14).

No emdashes. Change is atomic to this phase and confined to CommandPalette.slnf.

Replace the list-position frecency heuristic in RecentCommandsManager with a
real time-decayed signal: exponential recency decay (3-day half-life) combined
with log2(uses) for frequency, clamped to the previous ~0..70 range so the
ranker's within-tier math is unchanged and the tier still dominates ordering.

- HistoryItem gains a persisted LastUsed timestamp.
- Store cap grows from 50 to 500 entries.
- Legacy persisted items (no LastUsed) are treated as used one day ago so
  day-one ordering degrades to Uses-ordering instead of going all-equal.
- Add internal WithHistoryItem/GetCommandHistoryWeight overloads that take an
  explicit 'now' so tests can inject strictly-increasing timestamps.
- Mark the internal History property [JsonInclude] so history (and LastUsed)
  actually round-trips through the source-generated serializer; old empty
  state still deserializes cleanly.
- Rewrite the position-bucket tests as explicit time-decay tests; keep the
  tier-invariant tests unchanged in spirit.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@github-actions github-actions Bot added the Product-Command Palette Refers to the Command Palette utility label Jul 8, 2026
@michaeljolley michaeljolley marked this pull request as draft July 8, 2026 05:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Product-Command Palette Refers to the Command Palette utility

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant