feat(architecture-pool-supervisor): add milestone assignment to spec PRs #8188
@@ -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.
|
||||
|
||||
@@ -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
@@ -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"
|
||||
Reference in New Issue
Block a user