feat(projman): add sprint lifecycle state machine via milestone metadata
- New skill: sprint-lifecycle.md defines states, transitions, and check protocol - All sprint commands now check and set lifecycle state - States tracked in milestone description metadata (Sprint/Planning, Sprint/Executing, Sprint/Reviewing) - Out-of-order calls produce warnings with guidance - --force override available for all lifecycle checks - Added Sprint/* labels to label taxonomy documentation Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -90,6 +90,18 @@ Repository-level labels are specific to each project.
|
||||
- `Tech/Vue` (#42b883) - Vue.js frontend framework
|
||||
- `Tech/FastAPI` (#009688) - FastAPI backend framework
|
||||
|
||||
### Sprint Lifecycle (Milestone Metadata)
|
||||
|
||||
These are tracked as milestone description metadata, not as Gitea issue labels. They are documented here for completeness.
|
||||
|
||||
| Label | Description |
|
||||
|-------|-------------|
|
||||
| `Sprint/Planning` | Sprint planning in progress |
|
||||
| `Sprint/Executing` | Sprint execution in progress |
|
||||
| `Sprint/Reviewing` | Code review in progress |
|
||||
|
||||
**Note:** Lifecycle state is stored in milestone description as `**Sprint State:** Sprint/Executing`. See `skills/sprint-lifecycle.md` for state machine rules.
|
||||
|
||||
### Domain (2 labels)
|
||||
|
||||
Cross-plugin integration labels for domain-specific validation gates.
|
||||
|
||||
104
plugins/projman/skills/sprint-lifecycle.md
Normal file
104
plugins/projman/skills/sprint-lifecycle.md
Normal file
@@ -0,0 +1,104 @@
|
||||
---
|
||||
name: sprint-lifecycle
|
||||
description: Sprint lifecycle state machine using milestone labels
|
||||
---
|
||||
|
||||
# Sprint Lifecycle
|
||||
|
||||
## Purpose
|
||||
|
||||
Defines the valid sprint lifecycle states and transitions, enforced via labels on the sprint milestone. Each projman command checks the current state before executing and updates it on completion.
|
||||
|
||||
## When to Use
|
||||
|
||||
- **All sprint commands**: Check state on entry, update on exit
|
||||
- **Sprint status**: Display current lifecycle state
|
||||
|
||||
---
|
||||
|
||||
## State Machine
|
||||
|
||||
```
|
||||
idle -> Sprint/Planning -> Sprint/Executing -> Sprint/Reviewing -> idle
|
||||
(sprint-plan) (sprint-start) (review) (sprint-close)
|
||||
```
|
||||
|
||||
## State Labels
|
||||
|
||||
| Label | Set By | Meaning |
|
||||
|-------|--------|---------|
|
||||
| *(no Sprint/* label)* | `/sprint-close` or initial state | Idle - no active sprint phase |
|
||||
| `Sprint/Planning` | `/sprint-plan` | Planning in progress |
|
||||
| `Sprint/Executing` | `/sprint-start` | Execution in progress |
|
||||
| `Sprint/Reviewing` | `/review` | Code review in progress |
|
||||
|
||||
**Rule:** Only ONE `Sprint/*` label may exist on a milestone at a time. Setting a new one removes the previous one.
|
||||
|
||||
---
|
||||
|
||||
## State Transition Rules
|
||||
|
||||
| Command | Expected State | Sets State | On Wrong State |
|
||||
|---------|---------------|------------|----------------|
|
||||
| `/sprint-plan` | idle (no Sprint/* label) | `Sprint/Planning` | Warn: "Sprint is in [state]. Run `/sprint-close` first or use `--force` to re-plan." Allow with `--force`. |
|
||||
| `/sprint-start` | `Sprint/Planning` | `Sprint/Executing` | Warn: "Expected Sprint/Planning state but found [state]. Run `/sprint-plan` first or use `--force`." Allow with `--force`. |
|
||||
| `/review` | `Sprint/Executing` | `Sprint/Reviewing` | Warn: "Expected Sprint/Executing state but found [state]." Allow with `--force`. |
|
||||
| `/sprint-close` | `Sprint/Reviewing` | Remove all Sprint/* labels (idle) | Warn: "Expected Sprint/Reviewing state but found [state]. Run `/review` first or use `--force`." Allow with `--force`. |
|
||||
| `/sprint-status` | Any | No change (read-only) | Display current state in output. |
|
||||
|
||||
---
|
||||
|
||||
## Checking State (Protocol)
|
||||
|
||||
At command entry, before any other work:
|
||||
|
||||
1. Fetch the active milestone using `get_milestone`
|
||||
2. Check milestone description for `**Sprint State:**` line
|
||||
3. Compare against expected state for this command
|
||||
4. If mismatch: display warning with guidance, STOP unless `--force` provided
|
||||
5. If match: proceed and update state after command completes its primary work
|
||||
|
||||
**Implementation:** Use milestone description metadata. Add/update a line:
|
||||
```
|
||||
**Sprint State:** Sprint/Executing
|
||||
```
|
||||
|
||||
This avoids needing actual Gitea labels on milestones (which may not be supported). Parse this line to check state, update it to set state.
|
||||
|
||||
---
|
||||
|
||||
## Setting State
|
||||
|
||||
After command completes successfully:
|
||||
|
||||
1. Fetch current milestone description
|
||||
2. If `**Sprint State:**` line exists, replace it
|
||||
3. If not, append it to the end of the description
|
||||
4. Update milestone via `update_milestone`
|
||||
|
||||
**Format:** `**Sprint State:** <state>` where state is one of:
|
||||
- `Sprint/Planning`
|
||||
- `Sprint/Executing`
|
||||
- `Sprint/Reviewing`
|
||||
- (empty/removed for idle)
|
||||
|
||||
---
|
||||
|
||||
## Displaying State
|
||||
|
||||
In `/sprint-status` output, include:
|
||||
|
||||
```
|
||||
Sprint Phase: Executing (since 2026-02-01)
|
||||
```
|
||||
|
||||
Parse the milestone description for the `**Sprint State:**` line and display it prominently.
|
||||
|
||||
---
|
||||
|
||||
## Edge Cases
|
||||
|
||||
- **No active milestone**: State is implicitly `idle`
|
||||
- **Multiple milestones**: Use the open/active milestone. If multiple open, use the most recent.
|
||||
- **Milestone has no state line**: Treat as `idle`
|
||||
- **`--force` used**: Log to milestone: "Warning: Lifecycle state override: [command] forced from [actual] state on [date]"
|
||||
Reference in New Issue
Block a user