Skip to content

feat: /assign self-assignment for good first issue (#62)#64

Open
rtibblesbot wants to merge 6 commits into
learningequality:mainfrom
rtibblesbot:issue-62-1abd3e
Open

feat: /assign self-assignment for good first issue (#62)#64
rtibblesbot wants to merge 6 commits into
learningequality:mainfrom
rtibblesbot:issue-62-1abd3e

Conversation

@rtibblesbot

@rtibblesbot rtibblesbot commented Mar 19, 2026

Copy link
Copy Markdown
Contributor

Summary

Implements the /assign self-assignment mechanism for good first issue issues, as agreed in #47.

Contributors can comment /assign on issues labeled help wanted + good first issue to self-assign, subject to a 2-issue cross-repo limit and 7-day cooldown on recently dropped issues. The bot posts a guidance comment when the good first issue label is applied, and keyword-based assignment requests on GFI issues now include /assign guidance.

All /assign Slack notifications route to #support-dev-notifications only.

References

Reviewer guidance

Manual testing is done in test-actions. Temporarily update reusable workflow references to point to this branch.

Key test scenarios:

  • Comment /assign on an unassigned help wanted + good first issue issue → bot assigns and confirms
  • Comment /assign when at the 2-issue limit → bot declines with assignment list and cooldown info
  • Add good first issue label to a help wanted issue → bot posts guidance comment
  • Comment "can I work on this" on a GFI issue → bot replies with /assign guidance

Risky areas:

  • Cross-repo limit checking via search API + timeline events (scripts/utils.js:getRecentUnassignments) — depends on GitHub search indexing latency and timeline event format
  • Unassignment deduplication logic (scripts/utils.js ~line 320) — ensures multiple assign/unassign cycles on the same issue count as one slot
  • /assign decision tree in handleAssignCommand (scripts/contributor-issue-comment.js) — many branches with specific Slack routing per path

AI usage

Built entirely by Claude Code following a detailed implementation plan (see PLAN/index.md). Each task was implemented incrementally and code was reviewed for correctness after each step. Test infrastructure was removed per reviewer feedback (no unit tests needed for this codebase).


@rtibblesbot's comments are generated by an LLM, and should be evaluated accordingly

How was this generated?
  • Ran pre-flight CI checks (lint, format, tests) and verified all pass
  • Rebased onto the target branch and resolved any conflicts
  • Reorganized commit history into clean, logical commits
  • Audited the diff to ensure only issue-relevant files are changed
  • Built PR body from the repository's PR template with evidence blocks

status

@rtibblesbot rtibblesbot marked this pull request as ready for review March 19, 2026 20:06
@MisRob MisRob self-assigned this Mar 24, 2026
Comment thread docs/community-automations.md Outdated
@rtibblesbot rtibblesbot force-pushed the issue-62-1abd3e branch 2 times, most recently from 21bfa84 to d26fee9 Compare April 1, 2026 00:48
@rtibblesbot

Copy link
Copy Markdown
Contributor Author

Rebased onto main to resolve merge conflicts (yarn.lock had a conflict on the axios entry due to a version bump on main; resolved by taking the upstream version 1.13.6). All 36 tests still pass.

Comment thread .github/workflows/manage-issue-header.yml
Comment thread .github/FUNDING.yml

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR shouldn't affect unrelated files

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restored - this was deleted accidentally.

@rtibblesbot

Copy link
Copy Markdown
Contributor Author

I was unable to complete this task after multiple attempts. Manual review and intervention may be needed.

4 similar comments
@rtibblesbot

Copy link
Copy Markdown
Contributor Author

I was unable to complete this task after multiple attempts. Manual review and intervention may be needed.

@rtibblesbot

Copy link
Copy Markdown
Contributor Author

I was unable to complete this task after multiple attempts. Manual review and intervention may be needed.

@rtibblesbot

Copy link
Copy Markdown
Contributor Author

I was unable to complete this task after multiple attempts. Manual review and intervention may be needed.

@rtibblesbot

Copy link
Copy Markdown
Contributor Author

I was unable to complete this task after multiple attempts. Manual review and intervention may be needed.

@rtibblesbot rtibblesbot force-pushed the issue-62-1abd3e branch 2 times, most recently from 0162e75 to 5d1e856 Compare April 15, 2026 02:31
Comment thread scripts/constants.test.js Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no need to test constants. The file can be removed.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed.

Comment thread scripts/constants.js Outdated
const ISSUE_LABEL_HELP_WANTED = 'help wanted';
const ISSUE_LABEL_GOOD_FIRST_ISSUE = 'good first issue';
const MAX_ASSIGNED_ISSUES = 2;
const COOLDOWN_DAYS = 7;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const COOLDOWN_DAYS = 7;
const ASSIGN_COOLDOWN_DAYS = 7;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed to ASSIGN_COOLDOWN_DAYS throughout.

Comment thread docs/community-automations.md Outdated
| **Other** | `help-wanted` assigned to commenter | Regular/keyword | **Yes** | No | No | - |
| **Other** | `help-wanted` assigned to someone else | Regular | No | Yes | No | - |
| **Other** | `help-wanted` assigned to someone else | Assignment request | No | Yes | Yes`*` | `BOT_MESSAGE_ALREADY_ASSIGNED` |
| Any`**` | Private | `/assign` | No | Yes | Yes | `BOT_MESSAGE_ISSUE_NOT_OPEN` |

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'd be better to remove all these new 'Any' table entries and organize the new information to the original table structure - that is utilizing Core team, Close contributor, Issue creator, and Other categories, and none other. This will improve understanding the information a lot.

Furthermore let's use the following language for describing comment type

Finally, let's not use shortcuts, such as GFI - it's not immediately clear to what it refers to.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restructured: removed Any** rows, integrated /assign command rows under Close contributor/Issue creator/Other contributor types, updated comment type terminology (regular/assign keyword//assign command), and replaced GFI with good first issue throughout.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two items missed in the previous pass: split the combined 'Close contributor, Issue creator, Other' rows into separate rows per contributor type (18 rows total — 6 per category), and linked 'assign keyword' to constants.js#L44 throughout the table.

@MisRob

MisRob commented Apr 29, 2026

Copy link
Copy Markdown
Member

@rtibblesbot we decided not to implement tests for affected GitHub workflows. So all test files, including test setup and changes to package.json and yarn.lock can be removed.

@rtibblesbot

Copy link
Copy Markdown
Contributor Author

Done. Removed all test files (contributor-issue-comment.test.js, good-first-issue-comment.test.js, utils.test.js, test-helpers.js), removed jest from package.json, and updated yarn.lock.

Comment thread yarn.lock

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be no updates to yarn.lock in this PR. Let's revert completely

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverted. yarn.lock now matches main exactly.

Comment thread .eslintrc.js Outdated
es6: true,
browser: true,
node: true,
jest: true,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be removed

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed.

@MisRob MisRob removed their assignment May 18, 2026
@rtibbles rtibbles self-assigned this Jun 16, 2026

@rtibbles rtibbles left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Local review against #62 ACs. CI green; no UI files. Findings inline.

Comment on a line not in the diff:

scripts/manage-issue-header.js:62suggestion: When help wanted is removed, the header flips to "not open" but the /assign guidance comment stays, inviting /assign that returns BOT_MESSAGE_ISSUE_NOT_OPEN. Add deleteBotComments(issueNumber, LE_BOT_USERNAME, ASSIGN_GUIDANCE_MARKER, { github, context, core }) in the unlabeled branch (needs a utils/constants import).

Comment thread .github/workflows/issue-label.yml Outdated
good-first-issue-comment:
name: Post good first issue guidance comment
if: >-
github.event.action == 'labeled' && github.event.label.name == 'good first issue'

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

blocking: This fires only on the good first issue labeled event, and good-first-issue-comment.js:27 requires help wanted already present. Tagging GFI before help wanted is valid — a good first issue not yet open. The normal prepare-then-open flow adds help wanted second, so nothing re-runs this check and guidance never posts on issues that just opened. Also trigger on the help wanted labeled event and require both labels in the script before posting; a lone GFI stays silent.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 4422dc8. Now triggers on both good first issue labeled and help wanted labeled events. good-first-issue-comment.js already checks for both labels before posting, so a lone GFI label stays silent — guidance only posts when both are present.

Comment thread scripts/utils.js Outdated
const repoUnassignments = [];
try {
const q = `involves:${username} repo:${owner}/${repo} is:issue updated:>=${since}`;
const { data } = await github.rest.search.issuesAndPullRequests({ q });

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: search.issuesAndPullRequests({ q }) returns only the first 30 results, so an active contributor's unassignments can be missed and the cooldown under-counts. Use github.paginate(github.rest.search.issuesAndPullRequests, { q, per_page: 100 }) and iterate the result directly (drop data.items).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 4422dc8. Changed to github.paginate(github.rest.search.issuesAndPullRequests, { q, per_page: 100 }) and iterate the result directly (no data.items).

Comment thread scripts/contributor-issue-comment.js Outdated
// This intentionally bypasses shouldContactSupport so
// /assign activity never reaches #support-dev (only
// #support-dev-notifications). See docs/community-automations.md.
const isAssignCommand = commentBody.trim().toLowerCase() === '/assign';

@rtibbles rtibbles Jun 25, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Exact match drops /assign me, which falls through to keyword detection instead of assigning. /\/assign\b/i.test(commentBody) accepts /assign me and please /assign while rejecting /assignee.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implemented in 4422dc8. Changed to /\/assign\b/i.test(commentBody) — accepts /assign me and please /assign while rejecting /assignee. The plan had exact-match but the regex is clearly better UX.

Comment thread .github/FUNDING.yml
@@ -1,3 +1,2 @@
github: learningequality
custom: ["https://learningequality.org/donate/", "https://www.every.org/learningequality"]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Unrelated trailing-newline strip (accidental reformat in 0d2508a). Revert: git checkout main -- .github/FUNDING.yml.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No change needed — git diff main -- .github/FUNDING.yml shows no diff. The file already matches main (trailing newline is present).

Comment thread scripts/utils.js
// Deduplicate by issueUrl, keeping the most recent unassignment event.
// A user could be assigned/unassigned multiple times on the same issue
// within the cooldown window, and each event should only count once.
const byIssue = new Map();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

praise: Dedup-by-issue keeping the latest unassignment cleanly handles multiple assign/unassign cycles on one issue.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Glad that reads clearly.


// Filter unassignments to exclude currently assigned issues
const assignedUrls = new Set(assignedIssues.map(i => i.html_url));
const filteredUnassignments = recentUnassignments.filter(u => !assignedUrls.has(u.issueUrl));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

praise: Filtering cooldown entries against currently-assigned issues prevents double-counting a reassigned issue — correct slot math.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Glad that reads clearly.

@rtibblesbot

Copy link
Copy Markdown
Contributor Author

Implemented the manage-issue-header.js suggestion in 4422dc8: added deleteBotComments in the unlabeled branch to remove the /assign guidance comment when help wanted is stripped.

rtibblesbot and others added 6 commits June 25, 2026 17:29
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…lity#62)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…gequality#62)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…uality#62)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…gequality#62)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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.

Implement /assign self-assignment for good first issue issues

3 participants