Skip to content

Rework priority estimation GitHub action according to reach/impact/effort methodology #2615

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 47 additions & 8 deletions .github/workflows/priority-score.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,58 @@ jobs:
with:
github-token: ${{ secrets.YDBOT_TOKEN }}
script: |
const labelWeights = {
"prio/high": 1000,
"prio/medium": 500,
"prio/low": 100
// Priority estimation based on reach/impact/effort methodology
const reachWeights = {
"reach:high": 100,
"reach:medium": 75,
"reach:low": 50
};

const impactWeights = {
"impact:high": 200,
"impact:medium": 137.5,
"impact:low": 75
};

const effortWeights = {
"effort:high": 10,
"effort:medium": 5,
"effort:low": 2
};

const issue = context.payload.issue;
const labels = issue.labels.map(l => l.name);
const basePriority = Math.min(...labels.map(l => labelWeights[l] || 10), 1000);

const createdAt = new Date(issue.created_at);
const daysOld = Math.floor((Date.now() - createdAt.getTime()) / (1000 * 60 * 60 * 24));
const finalScore = basePriority + daysOld;
// Find reach, impact, and effort values from labels
let reach = null;
let impact = null;
let effort = null;

for (const label of labels) {
if (reachWeights[label] !== undefined) {
reach = reachWeights[label];
}
if (impactWeights[label] !== undefined) {
impact = impactWeights[label];
}
if (effortWeights[label] !== undefined) {
effort = effortWeights[label];
}
}

// Calculate priority score using formula: (reach * impact) / effort
let finalScore = 0;
if (reach !== null && impact !== null && effort !== null) {
finalScore = Math.round((reach * impact) / effort);
} else {
// Fallback to default values if labels are missing
const defaultReach = reach || 50; // default to medium-low reach
const defaultImpact = impact || 75; // default to low impact
const defaultEffort = effort || 5; // default to medium effort
finalScore = Math.round((defaultReach * defaultImpact) / defaultEffort);
}

console.log(`πŸ“Š Priority calculation: reach=${reach || 'default'}, impact=${impact || 'default'}, effort=${effort || 'default'} β†’ score=${finalScore}`);

const projectNumber = 24;
const org = "ydb-platform";
Expand Down
189 changes: 189 additions & 0 deletions priority-estimation-tests.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
# Priority Estimation Testing Guide

This document contains comprehensive test cases to validate the priority score estimation logic based on reach/impact/effort methodology.

## Methodology Overview

The priority score is calculated using the formula:

```
Priority Score = (Reach Γ— Impact) / Effort
```

### Label Mappings

**Reach Labels** (how many users/stakeholders are affected):

- `reach:high` β†’ 100
- `reach:medium` β†’ 75
- `reach:low` β†’ 50

**Impact Labels** (how much value/benefit):

- `impact:high` β†’ 200
- `impact:medium` β†’ 137.5
- `impact:low` β†’ 75

**Effort Labels** (how much work required):

- `effort:high` β†’ 10
- `effort:medium` β†’ 5
- `effort:low` β†’ 2

## Test Cases

### Test Case 1: Low Reach, Medium Impact, Medium Effort

1. Create an issue or use existing issue
2. Add labels: `reach:low`, `impact:medium`, `effort:medium`
3. Run the GitHub action (or trigger it by editing the issue)
4. **Expected Priority Score**: (50 Γ— 137.5) / 5 = **1,375**
5. Verify the score appears in the YDB UI project board under "CalculatedPriority" field

### Test Case 2: High Reach, High Impact, Low Effort (Highest Priority)

1. Create an issue or use existing issue
2. Add labels: `reach:high`, `impact:high`, `effort:low`
3. Run the GitHub action
4. **Expected Priority Score**: (100 Γ— 200) / 2 = **10,000**
5. Verify this is one of the highest priority scores

### Test Case 3: Low Reach, Low Impact, High Effort (Lowest Priority)

1. Create an issue or use existing issue
2. Add labels: `reach:low`, `impact:low`, `effort:high`
3. Run the GitHub action
4. **Expected Priority Score**: (50 Γ— 75) / 10 = **375**
5. Verify this is one of the lower priority scores

### Test Case 4: Medium Reach, High Impact, Medium Effort

1. Create an issue or use existing issue
2. Add labels: `reach:medium`, `impact:high`, `effort:medium`
3. Run the GitHub action
4. **Expected Priority Score**: (75 Γ— 200) / 5 = **3,000**
5. Verify this appears as a high-priority item

### Test Case 5: High Reach, Low Impact, High Effort

1. Create an issue or use existing issue
2. Add labels: `reach:high`, `impact:low`, `effort:high`
3. Run the GitHub action
4. **Expected Priority Score**: (100 Γ— 75) / 10 = **750**
5. Verify this gets moderate priority despite high reach

### Test Case 6: Missing Reach Label (Default Values)

1. Create an issue or use existing issue
2. Add labels: `impact:medium`, `effort:medium` (no reach label)
3. Run the GitHub action
4. **Expected Priority Score**: (50 Γ— 137.5) / 5 = **1,375** (uses default reach:low value)
5. Verify the action logs show "reach=default"

### Test Case 7: Missing Impact Label (Default Values)

1. Create an issue or use existing issue
2. Add labels: `reach:high`, `effort:low` (no impact label)
3. Run the GitHub action
4. **Expected Priority Score**: (100 Γ— 75) / 2 = **3,750** (uses default impact:low value)
5. Verify the action logs show "impact=default"

### Test Case 8: Missing Effort Label (Default Values)

1. Create an issue or use existing issue
2. Add labels: `reach:medium`, `impact:high` (no effort label)
3. Run the GitHub action
4. **Expected Priority Score**: (75 Γ— 200) / 5 = **3,000** (uses default effort:medium value)
5. Verify the action logs show "effort=default"

### Test Case 9: All Labels Missing (All Default Values)

1. Create an issue or use existing issue
2. Add no reach/impact/effort labels (or only unrelated labels)
3. Run the GitHub action
4. **Expected Priority Score**: (50 Γ— 75) / 5 = **750** (uses all default values)
5. Verify the action logs show "reach=default, impact=default, effort=default"

### Test Case 10: Label Updates Change Priority

1. Create an issue with labels: `reach:low`, `impact:low`, `effort:high`
2. Run the GitHub action
3. Verify initial score: (50 Γ— 75) / 10 = **375**
4. Update labels to: `reach:high`, `impact:high`, `effort:low`
5. Run the GitHub action again (by editing the issue)
6. **Expected New Priority Score**: (100 Γ— 200) / 2 = **10,000**
7. Verify the score updated correctly in the project board

### Test Case 11: Medium Values Across All Dimensions

1. Create an issue or use existing issue
2. Add labels: `reach:medium`, `impact:medium`, `effort:medium`
3. Run the GitHub action
4. **Expected Priority Score**: (75 Γ— 137.5) / 5 = **2,063** (rounded)
5. Verify this appears as a moderate priority item

### Test Case 12: Multiple Labels of Same Type (Last One Wins)

1. Create an issue or use existing issue
2. Add labels: `reach:low`, `reach:high`, `impact:medium`, `effort:low`
3. Run the GitHub action
4. **Expected Priority Score**: (100 Γ— 137.5) / 2 = **6,875** (uses reach:high as the last processed)
5. Verify the calculation uses the higher reach value

## Validation Steps

For each test case:

1. **Trigger the Action**: Edit the issue description or labels to trigger the workflow
2. **Check Action Logs**: Go to Actions tab β†’ Select the "Update Calculated Priority" run β†’ Check logs for calculation details
3. **Verify Project Board**: Navigate to the YDB UI project board and confirm the "CalculatedPriority" field shows the expected value
4. **Compare Relative Priorities**: Ensure issues with higher calculated scores appear higher in priority rankings

## Expected Log Format

The action should log calculation details in this format:

```
πŸ“Š Priority calculation: reach=50, impact=137.5, effort=5 β†’ score=1375
βœ… Updated CalculatedPriority of issue #123 to 1375
```

## Troubleshooting

- If the action doesn't trigger, check that the `YDBOT_TOKEN` secret has proper permissions
- If scores don't appear on the project board, verify the issue is added to project #24
- If calculations seem incorrect, check the action logs for the exact values used
- If default values aren't applied correctly, verify the fallback logic in the script

## Additional Test Cases (13-15)

### Test Case 13: Multiple Labels of Same Category (Overwrite Behavior)

1. Create an issue with labels: `reach:low`, `reach:medium`, `reach:high`, `impact:medium`, `effort:low`
2. Run the GitHub action
3. **Expected Priority Score**: (100 Γ— 137.5) / 2 = **6,875** (should use `reach:high` as the last processed)
4. Verify the action correctly handles multiple conflicting labels

### Test Case 14: Edge Case - Lowest Possible Score

1. Create an issue with labels: `reach:low`, `impact:low`, `effort:high`
2. Run the GitHub action
3. **Expected Priority Score**: (50 Γ— 75) / 10 = **375**
4. Verify this represents the minimum priority calculation

### Test Case 15: Edge Case - Highest Possible Score

1. Create an issue with labels: `reach:high`, `impact:high`, `effort:low`
2. Run the GitHub action
3. **Expected Priority Score**: (100 Γ— 200) / 2 = **10,000**
4. Verify this represents the maximum priority calculation

## Boundary Testing

Additional edge cases to consider:

- Issues with special characters in labels
- Issues not added to the project board
- Network failures during GraphQL API calls
- Issues with multiple reach/impact/effort labels (should use last processed value)
- Rounding behavior for non-integer results