diff --git a/.opencode/agents/architecture-pool-supervisor.md b/.opencode/agents/architecture-pool-supervisor.md index 67e4e49c7..009b9160a 100644 --- a/.opencode/agents/architecture-pool-supervisor.md +++ b/.opencode/agents/architecture-pool-supervisor.md @@ -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. diff --git a/CHANGELOG.md b/CHANGELOG.md index 46bd4bb64..24e7b55ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index f7f84a8a7..ff7795e84 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -7,7 +7,6 @@ * Jeffrey Phillips Freeman * Luis Mendes * Rui Hu -* HAL 9000 # 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. diff --git a/docs/development/agent-system-specification.md b/docs/development/agent-system-specification.md index f8c286929..e34dd8b84 100644 --- a/docs/development/agent-system-specification.md +++ b/docs/development/agent-system-specification.md @@ -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. diff --git a/features/architecture_pool_supervisor_milestone_assignment.feature b/features/architecture_pool_supervisor_milestone_assignment.feature new file mode 100644 index 000000000..6a8334ac8 --- /dev/null +++ b/features/architecture_pool_supervisor_milestone_assignment.feature @@ -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 diff --git a/features/steps/architecture_pool_supervisor_milestone_assignment_steps.py b/features/steps/architecture_pool_supervisor_milestone_assignment_steps.py new file mode 100644 index 000000000..f0cf64329 --- /dev/null +++ b/features/steps/architecture_pool_supervisor_milestone_assignment_steps.py @@ -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"