Testing Assignment Skill
Assign reviewed ADO work items to team members for testing. Distributes items evenly while respecting the rule: never assign to the person who resolved or reviewed the item.
Arguments
- •
--users "email1,email2,..."- Comma-separated list of team member emails to receive assignments
Process
1. Fetch Reviewed Items
bash
curl -s http://localhost:3003/api/sprint/reviewed-items
Returns JSON with sprintName and items[] containing:
- •
id,title,state,type,url - •
assignedTo- current assignee (skip if already set) - •
resolvedBy- display name of resolver - •
reviewedBy- display name of reviewer
2. Get Credentials from .env
Read C:\dev\ai\orch\.env for:
- •
ADO_ORG- Azure DevOps organization - •
ADO_PAT- Personal access token - •
ADO_PROJECT- Project name (e.g., BBNew)
3. Name-to-Email Mapping (Blue Billywig)
javascript
const nameToEmail = {
'Guido Hultink': 'g.hultink@bluebillywig.com',
'Martijn Bots': 'm.bots@bluebillywig.com',
'Janroel Koppen': 'j.koppen@bluebillywig.com',
'Vincent van Laar': 'v.vanlaar@bluebillywig.com',
'Jan ten Haaf': 'j.tenhaaf@bluebillywig.com',
'Max Mulder': 'm.mulder@bluebillywig.com',
'Simon Smulders': 's.smulders@bluebillywig.com',
'Peter van der Spek': 'p.vanderspek@bluebillywig.com',
'Olaf Timme': 'o.timme@bluebillywig.com'
};
4. Distribution Algorithm
Write a Node.js script in scratchpad:
javascript
// Track assignments per user
const userCounts = {};
users.forEach(u => userCounts[u] = 0);
const assignments = [];
const skipped = [];
items.forEach(item => {
// Skip items already assigned
if (item.assignedTo) {
skipped.push({id: item.id, reason: 'Already assigned to ' + item.assignedTo});
return;
}
const resolverEmail = nameToEmail[item.resolvedBy] || '';
const reviewerEmail = nameToEmail[item.reviewedBy] || '';
// Filter eligible users (not resolver, not reviewer)
const eligible = users.filter(u => u !== resolverEmail && u !== reviewerEmail);
if (eligible.length === 0) {
skipped.push({id: item.id, reason: 'No eligible users'});
return;
}
// Pick user with fewest assignments
eligible.sort((a, b) => userCounts[a] - userCounts[b]);
const assignee = eligible[0];
userCounts[assignee]++;
assignments.push({id: item.id, assignee});
});
5. Execute Assignments
ADO API to update AssignedTo:
javascript
async function assignItem(id, assignee) {
const url = `https://dev.azure.com/${ADO_ORG}/${PROJECT}/_apis/wit/workitems/${id}?api-version=7.1`;
const auth = Buffer.from(':' + ADO_PAT).toString('base64');
const body = [{ op: 'replace', path: '/fields/System.AssignedTo', value: assignee }];
const response = await fetch(url, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json-patch+json',
'Authorization': `Basic ${auth}`
},
body: JSON.stringify(body)
});
return response.ok;
}
6. Report Results
Output markdown table:
markdown
## Testing Assignment Complete **Sprint:** [Sprint Name] **Total Items:** N assigned **Skipped:** N **Users:** N ### Assignments by User | User | Items | Work Item IDs | |------|-------|---------------| | user@example.com | 5 | #123, #456, ... |
Rules
- •Never assign to resolver - The person in
resolvedByshould not test their own work - •Never assign to reviewer - The person in
reviewedByalready reviewed it - •Even distribution - Balance items across all eligible users
- •Skip already assigned - Items with
assignedToset are skipped - •Skip if impossible - If all selected users are ineligible, skip the item
Known Issues
- •
reviewedByfield requiresADO_REVIEWED_BY_FIELD=Microsoft.VSTS.Common.ReviewedByin .env (NOT Custom.ReviewedBy) - •Server must be restarted after .env changes
Example
code
/assign-testing --users "g.hultink@bluebillywig.com,m.bots@bluebillywig.com,j.koppen@bluebillywig.com"