feat(architecture-pool-supervisor): add milestone assignment to spec PRs #8188

Merged
HAL9000 merged 4 commits from add-milestone-assignment-to-spec-prs into master 2026-04-24 02:23:12 +00:00
6 changed files with 203 additions and 2 deletions
@@ -39,6 +39,7 @@ permission:
"forgejo_list_repo_milestones": allow
"forgejo_list_repo_pull_requests": allow
"forgejo_get_pull_request_by_index": allow
"forgejo_update_pull_request": allow
# CRITICAL: Never list repo-level labels — use org labels via forgejo-label-manager
"forgejo_list_repo_labels": deny
# CRITICAL: Label creation is COMPLETELY FORBIDDEN
@@ -100,6 +101,21 @@ When dispatching a worker, classify the change:
- **Major change** (new module, changed interfaces, restructured boundaries) — worker creates a PR with `needs feedback` label for human approval
- **Minor clarification** (typo fix, added detail, example) — worker commits directly
## PR Workflow for Major Changes
When a worker creates a PR for a major specification change, the following workflow must be followed:
1. **Create a feature branch** from the main branch with a descriptive name (e.g., `spec-auth-module-boundaries`)
2. **Commit spec changes** to the branch with a clear commit message following Conventional Changelog format
3. **Create a PR** with the `needs feedback` label to signal that human review and approval is required
4. **Assign the PR to the current active milestone** using `forgejo_update_pull_request` with the milestone ID
- Query available milestones using `forgejo_list_repo_milestones` to determine the current active milestone
- If no active milestone can be determined, skip milestone assignment rather than failing
- For spec PRs spanning multiple milestones, use the earliest affected milestone
5. **Post a comment** on the session state issue documenting the PR creation and linking to the PR
This workflow ensures that specification PRs are properly tracked within the project's milestone planning and remain visible in the project's issue/PR dashboard.
## Specification Structure
The specification must contain: Overview, Module Definitions (boundaries, responsibilities, public interfaces), Cross-Cutting Concerns (error handling, logging, configuration), Integration Points, and Milestone Plan.
+10
View File
@@ -5,6 +5,16 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
## [Unreleased]
### Added
- **Architecture Pool Supervisor Milestone Assignment** (#7521): Added a "PR Workflow
for Major Changes" section to the `architecture-pool-supervisor` agent definition
documenting the milestone assignment step for spec PRs. The agent now has
`forgejo_update_pull_request` permission to assign PRs to the current active
milestone after creation, improving traceability of specification changes within
project milestone planning. Includes BDD test coverage for the new workflow
documentation and permission configuration.
### Fixed
- **Atomic `load_from_metadata` for Autonomy Guardrails** (#7504): Fixed
+1 -1
View File
@@ -7,7 +7,6 @@
* Jeffrey Phillips Freeman <jeffrey.freeman@syncleus.com>
* Luis Mendes <luis.p.mendes@gmail.com>
* Rui Hu <rui.hu@cleverthis.com>
* HAL 9000 <hal9000@cleverthis.com>
# Details
@@ -24,3 +23,4 @@ Below are some of the specific details of various contributions.
* This project was made possible thanks to considerable donation of time, money, and resources by CleverThis, Inc.
* HAL 9000 has contributed automated bug fixes, CLI output formatting improvements, and ongoing maintenance as part of the CleverAgents automation system.
* HAL 9000 has contributed the file edit encoding parameter fix (PR #8258 / issue #7559).
* HAL 9000 has contributed the architecture-pool-supervisor milestone assignment feature (PR #8188 / issue #7521): added `forgejo_update_pull_request` permission and documented the PR workflow for major spec changes, enabling automatic milestone assignment for specification PRs.
@@ -1968,7 +1968,7 @@ Documented as the "#1 problem with this agent" due to historical creation of 48+
**Subagents**: `ref-reader`, `automation-tracking-manager`
**Workflow**: Checks for triggers every 30 minutes: new milestones without spec coverage, spec ambiguities reported by implementers, human requests for clarification, or initial bootstrap (no spec exists). When the spec grows beyond approximately 3,000 lines, transitions from a single `docs/specification.md` file to a `docs/specification/` directory with one file per module. Major architectural changes go through PRs with the `needs feedback` label; minor clarifications are committed directly.
**Workflow**: Checks for triggers every 30 minutes: new milestones without spec coverage, spec ambiguities reported by implementers, human requests for clarification, or initial bootstrap (no spec exists). When the spec grows beyond approximately 3,000 lines, transitions from a single `docs/specification.md` file to a `docs/specification/` directory with one file per module. Major architectural changes go through PRs with the `needs feedback` label; minor clarifications are committed directly. When creating a PR for a major spec change, the agent assigns it to the current active milestone using `forgejo_update_pull_request` (querying available milestones via `forgejo_list_repo_milestones`); if no active milestone can be determined, milestone assignment is skipped gracefully.
**Specification Structure**: Must contain Overview, Module Definitions (boundaries, responsibilities, public interfaces), Cross-Cutting Concerns (error handling, logging, configuration), Integration Points, and Milestone Plan.
@@ -0,0 +1,28 @@
Feature: Architecture pool supervisor milestone assignment
As a project manager
I want spec PRs to be automatically assigned to the current milestone
So that specification changes are properly tracked in project planning
Scenario: PR workflow documentation includes milestone assignment
Given the architecture-pool-supervisor.md file exists
When I read the "PR Workflow for Major Changes" section
Then the section should describe creating a feature branch
And the section should describe committing spec changes
And the section should describe creating a PR with "needs feedback" label
And the section should describe assigning the PR to the current active milestone
And the section should mention using "forgejo_update_pull_request" for milestone assignment
And the section should describe querying milestones using "forgejo_list_repo_milestones"
And the section should describe graceful handling when no active milestone exists
And the section should describe using the earliest milestone for multi-milestone specs
Scenario: Permissions allow milestone assignment
Given the architecture-pool-supervisor.md file exists
When I read the permissions section
Then "forgejo_update_pull_request" should be allowed
And "forgejo_list_repo_milestones" should be allowed
Scenario: Workflow ensures proper PR tracking
Given the architecture-pool-supervisor.md file exists
When I read the "PR Workflow for Major Changes" section
Then the workflow should ensure specification PRs are tracked within milestone planning
And the workflow should ensure PRs remain visible in the project's issue/PR dashboard
@@ -0,0 +1,147 @@
"""Step definitions for architecture pool supervisor milestone assignment."""
import re
from pathlib import Path
from typing import Any
from behave import given, then, when
@given("the architecture-pool-supervisor.md file exists")
def step_arch_supervisor_file_exists(context: Any) -> None:
"""Verify the architecture-pool-supervisor.md file exists."""
file_path = Path(".opencode/agents/architecture-pool-supervisor.md")
assert file_path.exists(), f"File {file_path} does not exist"
# Read the file content
with open(file_path, encoding="utf-8") as f:
context.file_content = f.read()
assert context.file_content, "File is empty"
@when('I read the "{section_name}" section')
def step_read_section(context: Any, section_name: str) -> None:
"""Extract a specific section from the file."""
# Find the section header
pattern = rf"## {re.escape(section_name)}\n(.*?)(?=\n## |\Z)"
match = re.search(pattern, context.file_content, re.DOTALL)
assert match, f"Section '{section_name}' not found in file"
context.section_content = match.group(1).strip()
@when("I read the permissions section")
def step_read_permissions_section(context: Any) -> None:
"""Extract the permissions section from the file."""
# Find the permissions section (between --- markers)
pattern = r"^---\n(.*?)\n---"
match = re.search(pattern, context.file_content, re.DOTALL | re.MULTILINE)
assert match, "Permissions section not found in file"
context.permissions_content = match.group(1).strip()
@then("the section should describe creating a feature branch")
def step_verify_feature_branch_description(context: Any) -> None:
"""Verify the section mentions creating a feature branch."""
assert "feature branch" in context.section_content.lower(), (
"Section should describe creating a feature branch"
)
@then("the section should describe committing spec changes")
def step_verify_commit_description(context: Any) -> None:
"""Verify the section mentions committing spec changes."""
assert "commit" in context.section_content.lower(), (
"Section should describe committing spec changes"
)
@then('the section should describe creating a PR with "{label}" label')
def step_verify_pr_label_description(context: Any, label: str) -> None:
"""Verify the section mentions creating a PR with the specified label."""
assert "pr" in context.section_content.lower(), (
"Section should describe creating a PR"
)
assert label.lower() in context.section_content.lower(), (
f"Section should mention '{label}' label"
)
@then("the section should describe assigning the PR to the current active milestone")
def step_verify_milestone_assignment_description(context: Any) -> None:
"""Verify the section describes milestone assignment."""
assert "milestone" in context.section_content.lower(), (
"Section should describe assigning PR to milestone"
)
assert "current active milestone" in context.section_content.lower(), (
"Section should mention 'current active milestone'"
)
@then('the section should mention using "{function_name}" for milestone assignment')
def step_verify_function_mention(context: Any, function_name: str) -> None:
"""Verify the section mentions the specific function."""
assert function_name in context.section_content, (
f"Section should mention '{function_name}' function"
)
@then('the section should describe querying milestones using "{function_name}"')
def step_verify_milestone_query_function(context: Any, function_name: str) -> None:
"""Verify the section mentions querying milestones."""
assert function_name in context.section_content, (
f"Section should mention '{function_name}' for querying milestones"
)
@then("the section should describe graceful handling when no active milestone exists")
def step_verify_graceful_handling(context: Any) -> None:
"""Verify the section describes graceful error handling."""
assert (
"skip" in context.section_content.lower()
or "graceful" in context.section_content.lower()
), "Section should describe graceful handling when no milestone exists"
@then(
"the section should describe using the earliest milestone for multi-milestone specs"
)
def step_verify_multi_milestone_handling(context: Any) -> None:
"""Verify the section describes handling multi-milestone specs."""
assert (
"earliest" in context.section_content.lower()
or "multiple" in context.section_content.lower()
), "Section should describe handling specs spanning multiple milestones"
@then('"{function_name}" should be allowed')
def step_verify_function_allowed(context: Any, function_name: str) -> None:
"""Verify the function is allowed in permissions."""
# Check if the function is listed as allowed
pattern = rf'"{function_name}":\s*allow'
assert re.search(pattern, context.permissions_content), (
f"Function '{function_name}' should be allowed in permissions"
)
@then(
"the workflow should ensure specification PRs are tracked within milestone planning"
)
def step_verify_milestone_tracking(context: Any) -> None:
"""Verify the workflow ensures milestone tracking."""
assert "milestone" in context.section_content.lower(), (
"Workflow should ensure milestone tracking"
)
@then(
"the workflow should ensure PRs remain visible in the project's issue/PR dashboard"
)
def step_verify_pr_visibility(context: Any) -> None:
"""Verify the workflow ensures PR visibility."""
assert (
"dashboard" in context.section_content.lower()
or "visible" in context.section_content.lower()
), "Workflow should ensure PR visibility in dashboard"