Skip to content

feat(attention): add explainable attention score and make it the default sort - #59

Merged
kasuken merged 1 commit into
mainfrom
feature/attention-score
Sep 14, 2026
Merged

kasuken merged 1 commit into
mainfrom
feature/attention-score

Conversation

@kasuken

@kasuken kasuken commented Sep 14, 2026

Copy link
Copy Markdown
Owner

Summary

Implements issue #33.

  • IAttentionScoreCalculator (new file, Needly.Application/Actions) — AttentionScoreResult (0-100, clamped) plus an ordered list of named AttentionScoreReason entries. Every point is traceable to a reason; nothing opaque.
  • AttentionScoreCalculator (new file, Needly.Infrastructure/Actions) — a pure calculation over VisibleAction, no DB or GitHub API access, cheap to call per row. Scoped to signals VisibleAction already exposes today: action type, at-risk flag, waiting duration, direct-vs-team assignment, pinned, draft state, diff size bucket, labels.
  • AttentionScoreOptions — every weight is IOptions-bound configuration, validated at startup, following the exact ActionRiskOptions/FollowUpOptions/DecideOptions convention already in this codebase.
  • Inbox.razor.cs — the "Attention" sort (previously just preserved InboxVisibilityService's fixed order) now actually ranks by computed score, oldest-waiting as tie-break. Still the default.
  • ActionRow — a score chip (62 · High) with a hover tooltip listing every contributing reason, e.g. +30 explicitly requested review · +20 at risk · +12 waiting 1 day.

Deliberately not wired in yet

Review risk (#34) and agent authorship (#35) are two of the signal families this score is meant to eventually include, but neither field exists on VisibleAction yet — both issues are in progress concurrently. This PR does not touch NeedlyAction, ActionFilter, GitHubWebhookModels.cs or InboxVisibilityService.cs at all, so it has no schema-level conflict with that work. Once #34/#35 land, extending the calculator's input with their two extra fields is a small, low-risk follow-up.

Known scope limits

  • TypeBasePoints (a Dictionary<string,int>) and WaitingTiers (a List<record>) are left at their C# defaults rather than also being wired into appsettings.json, to avoid unverified nested-collection configuration-binding risk. The scalar bonuses/penalties (at-risk, pinned, direct-assignment, draft, large-diff, urgent-label) are bound and validated at startup.
  • Per-user weight customization (the issue says "configurable per user") is not built — only per-installation defaults via configuration. A settings UI + per-user storage would be a follow-up.

Testing

  • dotnet build Needly.sln — 0 warnings, 0 errors
  • dotnet test Needly.sln — 388/388 passing (baseline 368 + 20 new)

Fixes #33

🤖 Generated with Claude Code

…ult sort

Implements issue #33:

- IAttentionScoreCalculator (new file, Needly.Application/Actions):
  AttentionScoreResult (0-100, clamped) + an ordered list of named
  AttentionScoreReason entries. Every point in the score is traceable to
  a reason; there is no opaque or hidden contribution.
- AttentionScoreCalculator (new file, Needly.Infrastructure/Actions):
  a pure calculation over VisibleAction -- no direct DB or GitHub API
  access, so it is fast, cheap to call per-row, and easy to test.
  Deliberately scoped to signals VisibleAction already exposes today
  (action type, at-risk flag, waiting duration, direct vs team
  assignment, pinned, draft state, diff size bucket, labels). Review
  risk (#34) and agent authorship (#35) are explicitly NOT wired in yet
  -- those fields don't exist on VisibleAction until those issues land
  -- so this ships independently without touching NeedlyAction,
  ActionFilter, GitHubWebhookModels.cs or InboxVisibilityService.cs at
  all, avoiding any schema-level conflict with that concurrent work.
- AttentionScoreOptions: every weight and threshold is configuration
  (IOptions-bound, validated at startup), not code, following the exact
  ActionRiskOptions/FollowUpOptions/DecideOptions convention already
  established in this codebase.
- Inbox.razor.cs: the "Attention" sort order (previously just preserved
  InboxVisibilityService's fixed pinned/at-risk/waiting order) now
  actually ranks by computed score, falling back to oldest-waiting as
  the tie-break. This is still the default sort.
- ActionRow: a score chip ("62 · High") with a hover tooltip listing
  every contributing reason, e.g. "+30 explicitly requested review ·
  +20 at risk · +12 waiting 1 day".

Known scope limits, by design:
- TypeBasePoints (a Dictionary<string,int>) and WaitingTiers (a
  List<record>) are left at their C# defaults rather than also being
  wired into appsettings.json, to avoid unverified nested-collection
  configuration-binding risk; the scalar bonuses/penalties are bound
  and validated at startup.
- Per-user weight customization (the issue's "configurable per user")
  is not built -- only per-installation defaults via configuration.
  A follow-up would need a settings UI and per-user storage.

Fixes #33

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@kasuken
kasuken merged commit 1d51937 into main Sep 14, 2026
@kasuken
kasuken deleted the feature/attention-score branch September 14, 2026 16:25
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.

Explainable attention score

1 participant