Skip to content

Miner dashboard change summary undercounts truncated signal groups #450

Description

@galuis116

Summary

buildRecommendationChange in src/services/miner-dashboard-recommendations.ts caps change-evidence labels at CHANGE_LABEL_LIMIT = 6, but builds the human-readable summary from the already-truncated limited slice instead of the full labels list. Labels are pushed in a fixed group order (repo_state ×5 → contributor_state ×2 → validation_state ×1 → policy_context ×2), so validation/policy are the first groups dropped — and when dropped, the summary omits them.

Evidence

// src/services/miner-dashboard-recommendations.ts:169
const limited = labels.slice(0, CHANGE_LABEL_LIMIT);
if (limited.length === 0) { /* unchanged */ }
const changedGroups = [...new Set(limited.map((label) => GROUP_TITLES[label.kind]))].join(", ");
//                                  ^^^^^^^ derived from the TRUNCATED slice
return { status: "changed", summary: `Changed since the previous run: ${changedGroups}.`, labels: limited };

Reproduction

A pack run where, for one repo, all of actionKind, lane, recommendation, priority bucket, and queue change (5 repo_state labels) plus contributor PR-state (1 contributor_state label), and validation blockers change:

  • labels = [5×repo_state, 1×contributor_state, 1×validation_state, …]
  • limited = labels.slice(0, 6) drops the validation_state label.
  • changedGroups = "Repo state, Contributor state" — Validation state is silently omitted from both labels and summary even though it changed.

Impact

The summary is the at-a-glance line a miner reads to decide whether to act. Undercounting changed groups — dropping precisely the validation/policy signals that matter most — misleads them into thinking blockers/policy are stable when they aren't. Same defect family as the already-accepted #383 / #398 / #408 truncation-undercount bugs.

Suggested fix

Compute the summary from the full labels set while keeping the display cap on the returned labels:

const limited = labels.slice(0, CHANGE_LABEL_LIMIT);
if (labels.length === 0) {
  return { status: "unchanged", summary: "No tracked evidence changed since the previous run.", labels: [] };
}
const changedGroups = [...new Set(labels.map((label) => GROUP_TITLES[label.kind]))].join(", ");
return { status: "changed", summary: `Changed since the previous run: ${changedGroups}.`, labels: limited };

Add a fixture where ≥7 fields change across all four groups and assert the summary still names Validation/Policy.

Metadata

Metadata

Assignees

No one assigned

    Labels

    slopAI slop and/or attempts to game additional points via manipulation or alt profiles.

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions