fix(provisioning): seed Challenge 1 at provision time and tolerate pending invitations#236
Conversation
…nding invitations Provisioned learning rooms started with an empty Issues tab: the Student Progression Bot only fires on issue close or manual dispatch, so nothing ever created Challenge 1 and the progression chain never began (reported in #226 and #216; every room in the self-paced-2026 cohort was affected). - provision-core: after content verification, seed the first challenge issue via an optional client capability; a seeding failure marks the learner failed and surfaces to the watchdog. - seed-first-challenge: new provisioning module that runs the learning-room challenge-progression script against the student repo with the App installation token. Idempotent via the script's own duplicate check. - challenge-progression: validate assignability in the repository (assignees endpoint) instead of global user existence. At provision time the collaborator invitation is still pending, so assignment 422s; the issue is now created unassigned and later challenges are assigned to whoever closes the previous one. - SPEC.md 7.2a/7.2b updated to match; HTML regenerated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Learning Room Validation ReportGreat work. Your changes look good. Resources |
|
Hi! I am Gandalf, your workshop agent. I bring a little magic to make this interaction clear, helpful, and fun. Here is my review of your pull request: Report StatusValidation Needs Attention [ACTION REQUIRED] Required Checks
Learning ResourcesBased on your changes, these guides might help: Automated validation by Learning Room Bot. Gandalf generated this review. Last updated: 2026-07-02T22:17:13.716Z |
Peer Review AssignedHi @accesswatch! Your PR has been automatically paired with @taylorarndt for peer review. For @taylorarndt:This is a great opportunity to practice code review skills! Here's what to look for: Content Quality:
Accessibility:
Documentation:
Review Guidelines:
Resources: Pairing by Learning Room Grouping Engine |
Progress UpdateGreat work, @accesswatch! Current Level: Explorer Available Challenges:
Keep going! |
There was a problem hiding this comment.
Pull request overview
This PR fixes a provisioning dead-start where newly created learning-room repos had no Challenge 1 issue, so the Student Progression Bot never triggered and learners could not begin the progression chain. It adds a provisioning-time seeding step (using the same progression script the student repo uses) and updates the progression script to tolerate pending collaborator invitations by creating the first issue unassigned when necessary.
Changes:
- Seed Challenge 1 during provisioning (post-workflow verification) by invoking the learning-room
challenge-progression.jsscript with the App installation token. - Update
challenge-progression.jsto validate assignee repo assignability (assignees endpoint) rather than global user existence, and to be importable for unit testing. - Update SPEC docs and regenerate committed HTML/search index outputs to reflect the new non-deferrable seeding requirement.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| SPEC.md | Updates provisioning spec to require seeding Challenge 1 at provision time and documents pending-invitation behavior. |
| learning-room/.github/scripts/challenge-progression.js | Adds repo-level assignee validation + exports helper for tests; guards main execution. |
| html/SPEC.html | Regenerated HTML to reflect SPEC updates. |
| html/search-index.json | Regenerated search index output after docs changes. |
| .github/scripts/provisioning/seed-first-challenge.js | New module that runs challenge-progression.js against the student repo to seed Challenge 1. |
| .github/scripts/provisioning/provision-core.js | Calls client.seedFirstChallenge() after required workflow verification. |
| .github/scripts/provisioning/provision-cli.js | Wires the seeder into the provisioning client used by the CLI. |
| .github/scripts/provisioning/tests/seed-first-challenge.test.js | Unit tests for the new seeding module (spawn behavior, error surfacing). |
| .github/scripts/provisioning/tests/provision-core.test.js | Adds provisioning tests for Challenge 1 seeding behavior and failure handling. |
| .github/scripts/tests/challenge-progression-assignee.test.js | Regression tests for pending-invitation assignee handling via exported helper. |
| } catch (error) { | ||
| log('WARN', `Assignee ${candidate} cannot be assigned yet (pending invitation or no repo access): ${error.message}`); | ||
| log('INFO', 'Issue will be created without an assignee.'); | ||
| return null; | ||
| } |
| /** | ||
| * First-challenge seeding for provisioning (SPEC.md section 7.2b step 3). | ||
| * |
| process.env.GITHUB_TOKEN = 'test-token'; | ||
| process.env.GITHUB_REPOSITORY = 'org/room'; | ||
| process.env.START_CHALLENGE = ''; | ||
| process.env.GITHUB_EVENT_NAME = ''; | ||
| process.env.CLOSED_ISSUE_TITLE = ''; | ||
|
|
||
| // The script resolves its issue-template directory from the working | ||
| // directory, so requiring it must happen from inside learning-room/. | ||
| process.chdir(path.join(__dirname, '..', '..', '..', 'learning-room')); | ||
|
|
||
| const { resolveValidAssignee } = require('../../../learning-room/.github/scripts/challenge-progression'); |
Summary
Provisioned learning rooms started with an empty Issues tab (#226, #216): the Student Progression Bot only fires on issue close or manual dispatch, so nothing ever created Challenge 1 and the progression chain never began. Every room in the self-paced-2026 cohort was affected.
Changes
GET /repos/{owner}/{repo}/assignees/{user}) instead of global user existence. At provision time the learner's collaborator invitation is still pending, so assigning them 422s; the issue is now created unassigned and later challenges are assigned to whoever closes the previous one.Testing
npm run test:provisioning: 80/80 pass (7 new tests, all watched fail first)npm run test:automation: 81/81 pass🤖 Generated with Claude Code