chore(agents): improve agent efficiency, scope control, and PR/issue lifecycle
CI / security (push) Successful in 1m3s
CI / quality (push) Successful in 32s
CI / build (push) Successful in 28s
CI / lint (push) Successful in 3m22s
CI / helm (push) Successful in 23s
CI / typecheck (push) Successful in 3m59s
CI / unit_tests (push) Successful in 6m54s
CI / e2e_tests (push) Successful in 17m40s
CI / docker (push) Successful in 12s
CI / integration_tests (push) Successful in 22m6s
CI / coverage (push) Has been cancelled
CI / benchmark-regression (push) Has been cancelled
CI / benchmark-publish (push) Has been cancelled
CI / status-check (push) Has been cancelled

Tiered worker allocation: implementors get full N workers, PR reviewers
N//2, and discovery agents (UAT, bug hunter, test-infra) N//4 to prevent
issue creation from outpacing implementation throughput.

Dead PR cleanup: PR reviewer now auto-closes stale, superseded,
unmergeable, and orphaned PRs every 5 cycles.

Post-merge issue closure: PR reviewer and self-reviewer now verify that
linked issues actually close after merge, removing satisfied dependency
links that block closure. Backlog groomer scans last 24h of merged PRs
and repairs open PR dependency health (reversed links, stale deps).

Closed-item guards: agents no longer wastefully modify closed issues/PRs.
Human liaison still responds to new human comments on closed items but
efficiently without re-triage. Backlog groomer prioritizes open items
first. System watchdog detects and flags closed-item interaction waste.

Scope control: non-critical findings from UAT testers and bug hunters now
route to backlog (no milestone + Priority/Backlog) instead of inflating
active milestones. Epic planner and issue creator skip converging
milestones. Project owner monitors and alerts on scope creep.
This commit is contained in:
2026-04-05 04:35:19 +00:00
parent 31f5997670
commit 329799a29e
11 changed files with 579 additions and 76 deletions
+119 -15
View File
@@ -85,28 +85,41 @@ actions_taken = []
LOOP FOREVER:
groom_cycle += 1
# ── Step 1: Fetch all open issues ────────────────────────────
all_issues = query Forgejo for all open issues (paginate if >100)
all_prs = query Forgejo for all open and recently closed PRs
# ── Step 1: Fetch open issues and PRs ────────────────────────
# GUARD: Primary grooming operates on OPEN items only.
# Closed-item hygiene runs AFTER open items are fully groomed.
all_open_issues = query Forgejo for all open issues (paginate if >100)
all_open_prs = query Forgejo for all open PRs
recently_merged_prs = query Forgejo for closed+merged PRs (last 24h)
# ── Step 2: Run all analysis passes ──────────────────────────
# ── Step 2: Run analysis passes on OPEN items (primary) ──────
# IMPORTANT: Filter out pull requests before duplicate detection.
# PRs are NOT issues — they deliver code for issues. A PR that
# "Closes #N" is the implementation of #N, NOT a duplicate.
issues_only = [i for i in all_issues if i.pull_request is None]
issues_only = [i for i in all_open_issues if i.pull_request is None]
findings = []
findings += check_duplicates(issues_only) # Issues only, never PRs
findings += check_orphans(all_issues)
findings += check_stale_issues(all_issues)
findings += check_label_quality(all_issues)
findings += check_priority_consistency(all_issues)
findings += check_closeable_issues(all_issues, all_prs)
findings += check_definition_of_done(all_issues)
findings += check_blocked_chain(all_issues)
findings += check_closed_issue_states(all_issues) # State reconciliation
findings += check_epic_completeness(all_issues)
findings += check_legendary_completeness(all_issues)
findings += check_orphans(all_open_issues)
findings += check_stale_issues(all_open_issues)
findings += check_label_quality(all_open_issues)
findings += check_priority_consistency(all_open_issues)
findings += check_closeable_issues(all_open_issues, all_open_prs)
findings += check_definition_of_done(all_open_issues)
findings += check_blocked_chain(all_open_issues)
findings += check_epic_completeness(all_open_issues)
findings += check_legendary_completeness(all_open_issues)
findings += check_merged_pr_issue_closure(recently_merged_prs) # Pass 15 (C)
findings += check_open_pr_dependency_health(all_open_prs) # Pass 16 (C)
findings += check_stale_prs(all_open_prs) # Pass 17 (B)
findings += check_scope_creep(all_open_issues) # Pass 18 (E)
# ── Step 2b: Closed-item hygiene (ONLY after open items done) ─
# Per policy: prioritize open ticket grooming. Only address closed
# tickets once open items are fully groomed this cycle.
if len(findings) == 0 or all open-item findings have been actioned:
recently_closed_issues = query Forgejo for closed issues (last 48h)
findings += check_closed_issue_states(recently_closed_issues) # Pass 9
# ── Step 3: Take action on findings ──────────────────────────
for finding in findings:
@@ -437,6 +450,97 @@ For each open legendary (`Type/Legendary`):
- For clear gaps: create the missing epic via Forgejo API
- For ambiguous gaps: post a comment requesting human guidance
### 15. Merged-PR Issue Closure Verification (every cycle)
For each PR merged in the last 24 hours (`recently_merged_prs`):
1. Extract linked issue numbers from the PR body (`Closes #N`, `Fixes #N`).
2. For each linked issue, fetch it from the Forgejo API.
3. If the issue is **still open**:
a. Fetch ALL dependency links on the issue (its "depends on" list).
b. For each dependency, check whether it is satisfied:
- Dependency is a PR that has been merged → **satisfied** (stale)
- Dependency is an issue that is closed → **satisfied** (stale)
- Dependency is open and legitimately blocks → **unsatisfied**
c. **Remove all satisfied (stale) dependency links** via the Forgejo
REST API (`DELETE /repos/{owner}/{repo}/issues/{blocker}/blocks`).
d. After removing stale dependencies, attempt to close the issue
and transition it to `State/Completed`.
e. If the issue still cannot be closed due to remaining real blockers,
post a diagnostic comment listing the unresolved dependencies.
**Action:** Close issues whose work is done, remove stale dependency links,
post diagnostic comments for issues that remain stuck.
### 16. Open PR Dependency Health (every cycle)
Scan ALL open PRs for incorrect or stale dependency links:
1. **Wrong direction detection (deadlock prevention):** If an issue is
recorded as **blocking** a PR (instead of the PR blocking the issue),
this creates a deadlock — Forgejo prevents the PR from merging until
the issue is resolved. Detect this and fix by:
- Removing the wrong-direction link
- Creating the correct link (PR blocks issue, issue depends on PR)
```bash
# Remove wrong direction: issue blocks PR
curl -s -X DELETE "https://<HOST>/api/v1/repos/<owner>/<repo>/issues/<ISSUE>/blocks" \
-H "Authorization: token <PAT>" \
-H "Content-Type: application/json" \
-d '{"owner": "<owner>", "repo": "<repo>", "index": <PR_NUMBER>}'
# Create correct direction: PR blocks issue
curl -s -X POST "https://<HOST>/api/v1/repos/<owner>/<repo>/issues/<PR_NUMBER>/blocks" \
-H "Authorization: token <PAT>" \
-H "Content-Type: application/json" \
-d '{"owner": "<owner>", "repo": "<repo>", "index": <ISSUE_NUMBER>}'
```
2. **Satisfied dependency removal:** If a PR depends on a blocker that is
already closed/merged, remove the stale dependency link.
3. **Missing PR→issue links:** If a PR body says `Closes #N` but no
Forgejo dependency link exists (PR blocks issue), create it.
**Action:** Fix reversed dependencies, remove stale links, create missing
links. Post a comment on each PR/issue where a fix is applied.
### 17. Stale PR Detection (every 3 cycles)
For all open PRs, detect patterns that indicate the PR should be closed:
- PRs with no milestone assigned (flag for milestone assignment or cleanup)
- PRs that duplicate the same work (same branch name or same linked issue)
- PRs whose target issue is in `State/Completed` or `State/Wont Do`
- PRs that have been open >72 hours with no review activity at all
**Action:** For definitive cases (linked issue closed, duplicate), post
comment and recommend closure. For ambiguous cases (no milestone, stale),
post a flagging comment. The PR reviewer supervisor handles actual closure.
### 18. Scope Creep Detection (every 3 cycles)
For each active milestone (state=open), calculate:
1. **Convergence ratio:** `closed_issues / (closed_issues + open_issues)`
2. **24-hour creation rate:** Count issues created in this milestone in
the last 24 hours.
3. **24-hour closure rate:** Count issues closed in this milestone in
the last 24 hours.
**Alert conditions:**
- If creation rate > closure rate * 2 for this milestone:
Post warning on session state issue:
```
[SCOPE ALERT] Milestone <name>: creation rate (<N>/24h) is >2x
closure rate (<M>/24h). Scope is growing faster than completion.
Non-critical new issues should use Priority/Backlog with no milestone.
```
- If milestone total issues grew >10% since last grooming cycle:
Flag for human review.
**Action:** Post scope warnings on the session state issue. Do NOT move
issues between milestones — that is the project owner's responsibility.
---
## Bot Signature (Required on ALL Forgejo Content)
+13 -2
View File
@@ -295,12 +295,18 @@ For the assigned module:
existing = search Forgejo for similar open issues
if duplicate found:
continue
# MILESTONE SCOPE GUARD: Only critical/security bugs get the
# active milestone. Non-critical findings go to the backlog
# (no milestone + Priority/Backlog) to prevent scope explosion.
is_critical = (finding.severity in ("critical", "security")
or finding.blocks_milestone_acceptance)
invoke ca-new-issue-creator with:
- Title: "BUG-HUNT: [<category>] <brief description>"
- Description: (see Finding Report Format below)
- Type: Bug
- Priority: based on severity assessment
- Milestone: current active milestone
- Priority: Priority/Critical if is_critical else Priority/Backlog
- Milestone: current active milestone if is_critical else NONE
```
5. **Exit** — Worker Mode completes after scanning the assigned module.
@@ -486,6 +492,11 @@ Before filing ANY issue, you MUST validate the finding:
the pool supervisor can dispatch new work.
- **NEVER file speculative or unverified findings.** See "Finding Validation"
section above. Every issue you file must have concrete code evidence.
- **Route non-critical findings to the backlog.** Only critical bugs and
security vulnerabilities that block the milestone's core acceptance criteria
get assigned to the active milestone. All other findings are created with
no milestone and `Priority/Backlog`. This prevents scope explosion in
active milestones.
---
+147 -4
View File
@@ -159,8 +159,106 @@ for s in json.loads(sys.stdin.read()):
LOOP FOREVER:
cycle += 1
# ── Step 0: Dead PR Cleanup (every 5 cycles) ────────────────
# Detect and close stale, superseded, or irrelevant open PRs.
# This prevents dead PRs from accumulating and wasting reviewer
# and CI resources.
if cycle % 5 == 0:
all_open_prs = query Forgejo for all open PRs targeting master/main
for pr in all_open_prs:
age_hours = (now - pr.created_at).total_hours()
# Case 1: Unmergeable (merge conflicts) for >6h with no
# recent commits — author has not rebased
if pr.mergeable == false:
last_commit_age = (now - pr.head_commit_date).total_hours()
if last_commit_age > 6:
post comment on PR:
"This PR has had merge conflicts for >{last_commit_age:.0f}
hours with no rebase attempt. Closing as stale. Please
rebase onto master and reopen if this work is still needed.
---
**Automated by CleverAgents Bot**
Supervisor: PR Review | Agent: ca-continuous-pr-reviewer"
close PR via forgejo_update_pull_request (state: closed)
reviewed_prs.add(pr.number)
pending_merge.pop(pr.number, None)
continue
# Case 2: Superseded by a newer PR on the same branch
same_branch_prs = [p for p in all_open_prs
if p.head.ref == pr.head.ref
and p.number != pr.number
and p.created_at > pr.created_at]
if same_branch_prs:
newer = same_branch_prs[0]
post comment on PR:
"Superseded by PR #{newer.number} (same branch, newer).
Closing this PR.
---
**Automated by CleverAgents Bot**
Supervisor: PR Review | Agent: ca-continuous-pr-reviewer"
close PR via forgejo_update_pull_request (state: closed)
reviewed_prs.add(pr.number)
pending_merge.pop(pr.number, None)
continue
# Case 3: Linked issue is already closed/completed
linked_issue_num = extract_issue_number_from_body(pr.body)
if linked_issue_num:
linked_issue = fetch issue via Forgejo API
if linked_issue.state == "closed":
post comment on PR:
"Linked issue #{linked_issue_num} is already closed.
This PR is no longer needed. Closing.
---
**Automated by CleverAgents Bot**
Supervisor: PR Review | Agent: ca-continuous-pr-reviewer"
close PR via forgejo_update_pull_request (state: closed)
reviewed_prs.add(pr.number)
pending_merge.pop(pr.number, None)
continue
# Case 4: CI permanently failing + no activity for >48h
if age_hours > 48:
statuses = query commit statuses for pr.head.sha
ci_failing = any(s.state == "failure" for s in statuses)
comments = fetch PR comments
last_activity = max(c.created_at for c in comments) if comments else pr.created_at
activity_age_hours = (now - last_activity).total_hours()
if ci_failing and activity_age_hours > 24:
post comment on PR:
"This PR has had failing CI for >{age_hours:.0f} hours
with no remediation activity in >{activity_age_hours:.0f}
hours. Closing as stale.
---
**Automated by CleverAgents Bot**
Supervisor: PR Review | Agent: ca-continuous-pr-reviewer"
close PR via forgejo_update_pull_request (state: closed)
reviewed_prs.add(pr.number)
pending_merge.pop(pr.number, None)
continue
# ── Step 1: Discover work ────────────────────────────────────
open_prs = query Forgejo for all open PRs targeting master/main
# GUARD: Only discover OPEN PRs. Never touch closed/merged PRs.
open_prs = query Forgejo for all open PRs targeting master/main (state=open)
# Prune tracking sets: remove any PR that was closed/merged externally
for pr_number in list(reviewed_prs):
if pr_number not in [p.number for p in open_prs]:
# PR was closed or merged outside our control — stop tracking
reviewed_prs.discard(pr_number)
for pr_number in list(pending_merge.keys()):
if pr_number not in [p.number for p in open_prs]:
pr_state = query Forgejo for PR state
if pr_state == "closed" and pr.merged:
# Merged externally — good, stop tracking
pass
pending_merge.pop(pr_number, None)
# Build work list from three sources:
work_items = []
@@ -334,8 +432,9 @@ LOOP FOREVER:
reviewed_prs.add(pr_number)
pending_merge.pop(pr_number, None)
# ── Step 5: Check for scheduled merges that completed ───────
# PRs with merge_when_checks_succeed may have merged since last cycle
# ── Step 5: Check for scheduled merges + verify issue closure
# PRs with merge_when_checks_succeed may have merged since last cycle.
# For ALL recently merged PRs, verify the linked issue was closed.
for pr_number in list(pending_merge.keys()):
if pending_merge[pr_number].last_status == "merge_scheduled":
pr = query Forgejo for PR #pr_number
@@ -344,7 +443,51 @@ LOOP FOREVER:
del pending_merge[pr_number]
# Post confirmation on linked issue
post comment on linked issue:
"PR #<pr_number> has been merged (scheduled merge completed)."
"PR #<pr_number> has been merged (scheduled merge completed).
---
**Automated by CleverAgents Bot**
Supervisor: PR Review | Agent: ca-continuous-pr-reviewer"
# VERIFY linked issue was actually closed
verify_linked_issue_closed(pr)
# ── Step 5b: Post-merge issue closure verification ───────────
# For PRs that were merged in Step 4 (this cycle), verify that
# their linked issues were properly closed. Dependencies may
# prevent auto-close even when the PR body says "Closes #N".
for pr_number in recently_merged_this_cycle:
verify_linked_issue_closed(pr_number)
# Helper function used above:
# function verify_linked_issue_closed(pr_or_number):
# linked_issue_num = extract issue number from PR body
# if not linked_issue_num: return
# issue = fetch issue via Forgejo API
# if issue.state == "open":
# # Issue should be closed but isn't — check dependencies
# deps = fetch dependency links for this issue (depends_on list)
# stale_deps = []
# for dep in deps:
# dep_item = fetch the blocking item
# if dep_item.state == "closed" or (dep_item is PR and dep_item.merged):
# stale_deps.append(dep) # This dependency is satisfied
#
# # Remove satisfied (stale) dependencies via REST API:
# for dep in stale_deps:
# curl -s -X DELETE ".../issues/{dep.number}/blocks" ...
#
# # Try to close the issue now
# if all dependencies resolved or removed:
# transition issue to State/Completed
# close issue via API
# post comment: "Issue closed after removing satisfied
# dependency links. PR #{pr_number} was already merged."
# else:
# post comment: "PR #{pr_number} merged but this issue
# remains open due to unresolved dependencies:
# <list remaining blockers>. Backlog groomer will
# review these dependency links."
# ── Step 6: Update clone for next cycle ──────────────────────
cd "$CLONE_DIR"
+38 -6
View File
@@ -62,25 +62,57 @@ SERVER = "http://localhost:4096"
LOOP FOREVER:
cycle += 1
# Query all milestones
milestones = query Forgejo for all milestones
# Query all OPEN milestones only — never plan for closed milestones
milestones = query Forgejo for milestones with state=open
# Check for triggers:
for milestone in milestones:
# SCOPE GUARD: Skip converging milestones
# A milestone is converging when closed_issues > open_issues.
# Adding new issues to a converging milestone defeats convergence.
if milestone.closed_issues > milestone.open_issues and milestone.open_issues > 0:
continue # Milestone is converging — do not add new issues
issues = query Forgejo for issues in this milestone
if len(issues) == 0:
# Milestone needs planning
plan_milestone(milestone)
# Check for incomplete epics
epics_without_children = find_epics_with_no_blockers()
if epics_without_children:
complete_epic_planning(epics_without_children)
# Check for incomplete epics — but ONLY for open epics
# Never plan children for closed or completed epics
open_epics = find_open_epics_with_no_blockers()
if open_epics:
# Filter out epics in converging milestones
plannable_epics = []
for epic in open_epics:
if epic.milestone:
ms = epic.milestone
if ms.closed_issues > ms.open_issues and ms.open_issues > 0:
continue # Skip epics in converging milestones
plannable_epics.append(epic)
if plannable_epics:
complete_epic_planning(plannable_epics)
# Sleep 10 minutes between polls
bash("sleep 600", timeout=1200000)
```
### Milestone Scope Guard
**CRITICAL:** Do NOT create new issues in milestones where `closed_issues >
open_issues` (the milestone is converging toward completion). Adding new
epics or issues to converging milestones prevents them from ever finishing.
When discovering work that could belong to a converging milestone:
- Create the issue with **no milestone** and `Priority/Backlog` label
- Post a note: "This issue was identified during planning but the target
milestone is converging. Placed in backlog for human review."
This guard does NOT apply to milestones with zero issues (fresh milestones
that need initial planning) or milestones where open > closed (still in
active development phase).
## Setup
You receive on first invocation:
+19 -1
View File
@@ -142,6 +142,8 @@ LOOP FOREVER:
continue # Skip automated claim comments
if "checkpoint" in comment.body.lower() and "phase" in comment.body.lower():
continue # Skip session state checkpoints
if "Automated by CleverAgents Bot" in comment.body:
continue # Skip bot-generated comments
new_activity.comments.append(comment)
# 1c: New PR reviews by humans
@@ -329,7 +331,23 @@ Before responding, read:
- The specification section relevant to the issue (if applicable)
- Any linked issues or PRs
### 2. Determine Comment Type
### 2. Check if the Issue/PR is Closed
**If the comment is on a closed issue or merged/closed PR**, respond
efficiently without full re-triage:
| Scenario | Response |
|---|---|
| Human asks a question on a closed issue | Answer the question helpfully using context from the issue. Do NOT re-triage or modify labels. |
| Human requests reopening | Explain that per CONTRIBUTING.md reopening is not permitted. Offer to create a NEW issue for the follow-up work. |
| Human reports a related bug on a closed issue | Acknowledge and create a new bug issue (via `ca-new-issue-creator`). Link it to the same parent Epic. |
| Human posts general feedback on a closed issue | Acknowledge briefly. No further action needed. |
**Key rule:** Never extensively modify labels, milestones, or state on
closed items. Keep responses brief and action-oriented. If new work is
needed, create a new issue rather than modifying the closed one.
### 3. Determine Comment Type (for open items)
| Comment Type | Response Strategy |
|---|---|
+37 -4
View File
@@ -75,6 +75,36 @@ Follow the format specified in CONTRIBUTING.md "Creating Issues":
- Coverage >= 97%
```
## Milestone Scope Guard
When creating issues discovered during autonomous operation (by UAT testers,
bug hunters, architecture guards, or other discovery agents), apply these
routing rules to prevent scope creep in active milestones:
1. **Critical bugs (`Priority/Critical` + `Type/Bug`)**: Assign to the
milestone where the bug was found. These are blocking and must be fixed
in the current cycle.
2. **All other discovered issues** (non-critical bugs, improvements, spec
deviations, refactoring, "should have" features): Do NOT assign a
milestone. Set `Priority/Backlog`. These appear in the backlog for human
review and future milestone assignment.
3. **Exception**: If the caller explicitly specifies a milestone AND the
issue is clearly essential to that milestone's core acceptance criteria,
assign it to the specified milestone.
4. **NEVER add non-critical issues to milestones where closed issues
outnumber open issues** (the milestone is converging toward completion).
Adding new work to converging milestones defeats convergence.
When routing an issue to backlog, post this note in the issue body:
```
> **Backlog note:** This issue was discovered during autonomous operation
> on milestone <M>. It does not block milestone completion and has been
> placed in the backlog for human review and future milestone assignment.
```
## Process
1. **Determine issue scope**:
@@ -85,14 +115,17 @@ Follow the format specified in CONTRIBUTING.md "Creating Issues":
- A clear, descriptive title
- The body in the format above
- Appropriate labels: `State/Unverified`, a `Priority/*` label,
a `MoSCoW/*` label, and a `Type/*` label
- The correct milestone
and a `Type/*` label
- The correct milestone (per Milestone Scope Guard above — critical
bugs get the source milestone, everything else gets no milestone
with `Priority/Backlog`)
3. **Set labels via Forgejo API** — every issue MUST have ALL of these:
- `State/Unverified` — use `forgejo_add_issue_labels`
- One `Type/*` label (Bug, Feature, Task, etc.) — use `forgejo_add_issue_labels`
- One `Priority/*` label (use `Priority/Backlog` if unsure) — use `forgejo_add_issue_labels`
- Do NOT assign `MoSCoW/*` labels (project owner only)
- One `Priority/*` label — use `forgejo_add_issue_labels`. For non-critical
issues routed to backlog per the Milestone Scope Guard, use `Priority/Backlog`.
- Do NOT assign `MoSCoW/*` labels (project owner only per CONTRIBUTING.md)
4. **Set milestone via Forgejo API**:
- Use `forgejo_update_issue` to assign the correct milestone
+37
View File
@@ -241,6 +241,43 @@ If the PR meets all criteria:
**A merged PR whose issue still shows State/Unverified or State/In Review
is a data integrity failure. This step is as important as the merge itself.**
5. **Verify the issue actually closed.** After transitioning to
`State/Completed`, re-fetch the issue from the Forgejo API and check
whether it is actually closed (state=closed). Dependencies may prevent
Forgejo from closing the issue even with the correct label.
a. Re-fetch the issue via `forgejo_get_issue_by_index`.
b. If the issue is **still open** despite having `State/Completed`:
- Fetch all dependency links on the issue (its "depends on" list)
via Forgejo REST API.
- For each dependency, check whether it is satisfied:
* If the dependency is a PR that has been merged → satisfied
* If the dependency is an issue that is closed → satisfied
* If the dependency is open and legitimately blocks → unsatisfied
- **Remove all satisfied (stale) dependency links** via:
```
curl -s -X DELETE "https://<HOST>/api/v1/repos/<owner>/<repo>/issues/<BLOCKER>/blocks" \
-H "Authorization: token <PAT>" \
-H "Content-Type: application/json" \
-d '{"owner": "<owner>", "repo": "<repo>", "index": <THIS_ISSUE>}'
```
- After removing stale dependencies, attempt to close the issue
via `forgejo_issue_state_change(state: "closed")`.
- If closure succeeds, post confirmation comment.
- If closure still fails (remaining real blockers), post a
diagnostic comment listing the unresolved blocking dependencies
so the backlog groomer can investigate:
```
"PR #<N> merged but this issue remains open due to unresolved
dependencies: <list>. The backlog groomer will review these
dependency links.
---
**Automated by CleverAgents Bot**
Supervisor: PR Review | Agent: ca-pr-self-reviewer"
```
c. If the issue closed successfully, no further action needed.
#### REQUEST CHANGES → Send Back
If the PR has issues that must be fixed:
+20 -1
View File
@@ -116,7 +116,10 @@ LOOP FOREVER:
discover_developer_expertise()
# ── Step 2: Triage unverified issues ─────────────────────────
unverified = query Forgejo for all issues with label "State/Unverified"
# GUARD: Only triage OPEN unverified issues. Skip any issue
# where state=closed even if it still carries State/Unverified.
unverified = query Forgejo for open issues with label "State/Unverified"
unverified = [i for i in unverified if i.state == "open"]
for issue in unverified:
if issue.number in triaged_issues:
@@ -341,6 +344,22 @@ Every 10th cycle, review the full project state:
- If >50% of Must Have items are still open and the milestone is >50%
through its time window, post a warning on the session state issue
5. **Milestone scope health check**:
For each active milestone:
- Calculate convergence: `closed / (open + closed)`
- Calculate 24h creation rate vs 24h closure rate
- If creation_rate > closure_rate * 2:
Post warning on session state issue:
```
[SCOPE ALERT] Milestone <name>: <creation_rate> issues created
vs <closure_rate> issues closed in last 24h. Scope is expanding
faster than completion. Non-critical new issues should be routed
to the backlog (no milestone + Priority/Backlog) rather than
assigned to this milestone.
```
- If a milestone's total issue count grew >10% since last cycle:
Post flagging comment requesting human review of the new additions
---
## Behavior: Follow Up on Pending Questions
+72
View File
@@ -152,6 +152,13 @@ LOOP FOREVER:
if cycle % 6 == 0:
findings += audit_deep_session_introspection()
# ── Audit 13: Closed Item Interaction Detection (every 3rd) ──
# Detect agents that are modifying closed issues/PRs. This wastes
# resources and can create confusion (batch label updates on closed
# items, comments on merged PRs, etc.)
if cycle % 3 == 0:
findings += audit_closed_item_interactions()
# ── Take Action on Findings ──────────────────────────────────
for finding in findings:
take_action(finding)
@@ -1182,6 +1189,71 @@ function dispatch_one_off(agent_name, finding):
Finding: <finding.detail>"
```
### Audit 13: Closed Item Interaction Detection (Every 3rd Cycle)
**Purpose:** Detect agents that are wastefully modifying closed issues or
merged/closed PRs. These operations waste API calls and agent context, and
can create confusion (batch label updates, comments on resolved items).
**Exceptions:** The following interactions with closed items are legitimate:
- Human-liaison responding to new human comments on closed issues
- Backlog groomer reconciling state labels on recently closed issues (after
finishing all open-item grooming)
- PR reviewer verifying linked issue closure after a merge
```
function audit_closed_item_interactions():
findings = []
# Check recent Forgejo activity on closed issues and PRs
# Look for bot comments posted on closed items in the last 30 min
recent_closed_issues = query Forgejo for closed issues updated in last 30 min
recent_closed_prs = query Forgejo for closed PRs updated in last 30 min
for item in recent_closed_issues + recent_closed_prs:
comments = fetch comments on item since last audit cycle
bot_comments = [c for c in comments
if c.user.login == <FORGEJO_USERNAME>
and "Automated by CleverAgents Bot" in c.body]
for comment in bot_comments:
# Extract which agent posted this
agent_name = extract agent name from bot signature
# Check if this is a legitimate exception
if agent_name == "ca-human-liaison":
continue # Liaison may respond to human comments on closed items
if agent_name == "ca-backlog-groomer" and "State label reconciliation" in comment.body:
continue # Groomer legitimately reconciles closed issue states
if agent_name in ("ca-pr-self-reviewer", "ca-continuous-pr-reviewer"):
if "merged" in comment.body.lower() or "closure" in comment.body.lower():
continue # Post-merge verification is legitimate
# Everything else is suspect
findings.append({
severity: "MEDIUM",
type: "closed_item_interaction",
detail: f"Agent '{agent_name}' posted a comment on closed "
f"{'issue' if not item.pull_request else 'PR'} "
f"#{item.number}. This may be wasteful. "
f"Comment excerpt: {comment.body[:100]}",
item_number: item.number,
agent: agent_name
})
# Also check for label modifications on closed items
# (via session introspection — check for forgejo_add_issue_labels
# calls targeting closed items)
# This is sampled via the deep introspection in Audit 12.
return findings
```
**Action for findings:** If the same agent repeatedly interacts with closed
items (3+ times across audit cycles), create a `needs feedback` issue
suggesting the agent definition be updated to include a closed-item guard.
---
## Health Signaling
+10 -1
View File
@@ -386,6 +386,10 @@ LOOP:
continue
# Create the bug issue
# MILESTONE SCOPE GUARD: Only critical bugs get the source
# milestone. Non-critical findings go to the backlog (no
# milestone + Priority/Backlog) to prevent scope explosion.
is_critical = (severity == "critical" or blocks_milestone_acceptance)
invoke ca-new-issue-creator with:
- Description: detailed bug report including:
- What was tested
@@ -394,7 +398,8 @@ LOOP:
- Steps to reproduce (for runtime issues)
- Code location (for code issues)
- Type: Bug
- Priority: based on severity
- Priority: Priority/Critical if is_critical else Priority/Backlog
- Milestone: source milestone if is_critical else NONE
- Title prefix: "UAT: <brief description>"
bugs_found.append(issue)
@@ -472,6 +477,10 @@ No exceptions — every comment, every issue body, every PR description.
vs actual behavior, and code locations.
- **Don't file cosmetic issues unless the spec explicitly requires specific
output formatting.** Focus on functional correctness.
- **Route non-critical findings to the backlog.** Only critical bugs that
block the milestone's core acceptance criteria get assigned to the source
milestone. All other findings are created with no milestone and
`Priority/Backlog`. This prevents scope explosion in active milestones.
- **Coordinate with other instances.** Check session state comments to avoid
testing the same features another instance is already covering.
- **If runtime testing fails to set up**, fall back to code-level analysis
+67 -42
View File
@@ -3,16 +3,18 @@ description: >
Autonomous product builder with pool-supervisor parallel execution. Takes a
product vision and builds the entire product from scratch — or picks up an
existing project mid-development. Launches ONE pool supervisor per work
category, each managing N parallel workers internally
(N = CA_MAX_PARALLEL_WORKERS): implementor pool, PR reviewer pool, UAT
tester pool, bug hunter pool, test infrastructure improver pool, architecture
guard, architect, epic planner, human liaison, agent evolver, backlog groomer,
spec updater, docs writer, timeline updater, project owner, and system
watchdog (16 total). Each pool supervisor maintains N active workers at all
times, immediately re-dispatching as workers complete — no batch-and-wait
bottlenecks. All agents coordinate exclusively through Forgejo issues, PRs,
and comments. Persists all state via Forgejo comments for crash-proof
resumability. Never terminates until the product is verified complete.
category, each managing parallel workers internally using a tiered allocation
based on CA_MAX_PARALLEL_WORKERS (N): implementor pool (full N), PR reviewer
pool (N//2), UAT tester pool (N//4), bug hunter pool (N//4), test
infrastructure improver pool (N//4), plus 11 singleton supervisors
(architecture guard, architect, epic planner, human liaison, agent evolver,
backlog groomer, spec updater, docs writer, timeline updater, project owner,
and system watchdog) — 16 total. Tiered allocation ensures implementors
dominate throughput while issue-discovery agents (UAT, bugs) run at reduced
capacity to prevent scope explosion. All agents coordinate exclusively
through Forgejo issues, PRs, and comments. Persists all state via Forgejo
comments for crash-proof resumability. Never terminates until the product is
verified complete.
mode: primary
temperature: 0.1
color: primary
@@ -101,6 +103,26 @@ before proceeding.
**Max parallel workers** is optional. If `CA_MAX_PARALLEL_WORKERS` is unset or
empty, default to **4**. Read it via `echo $CA_MAX_PARALLEL_WORKERS`.
### Worker Allocation Tiers
Not all supervisor pools need the same number of workers. Implementors should
dominate throughput because they close issues; issue-discovery agents (UAT,
bug hunting) generate new issues and should run at reduced capacity to prevent
scope explosion. Compute these values once from N at startup:
```
N = CA_MAX_PARALLEL_WORKERS # e.g. 8
N_FULL = N # Implementors: 8
N_HALF = max(1, N // 2) # PR Reviewers: 4
N_QUARTER = max(1, N // 4) # UAT, Bug hunters, Test infra: 2
```
| Tier | Formula | Used By | Rationale |
|------|---------|---------|-----------|
| Full (`N_FULL`) | `N` | issue-implementor | Closes issues — maximum throughput |
| Half (`N_HALF`) | `max(1, N // 2)` | ca-continuous-pr-reviewer | Must keep up with implementation but doesn't need 1:1 |
| Quarter (`N_QUARTER`) | `max(1, N // 4)` | ca-uat-tester, ca-bug-hunter, ca-test-infra-improver | These discover issues — capping prevents scope explosion |
### Repository Detection
The repository is determined by reading the git remote origin URL from the
@@ -332,30 +354,30 @@ never passes data between supervisors and never tells them what to do.
```
ALL SUPERVISORS RUN CONTINUOUSLY — THEY ARE SERVICES, NOT BATCH JOBS:
Stream Category Supervisors Internal Workers Lifecycle
──────────────────────── ─────────── ────────────────── ──────────────
Implementation 1 N issue-workers Continuous (polls for new issues)
PR Review 1 N reviewers Continuous (polls for new PRs)
UAT Testing 1 N feature testers Continuous (retests on new code)
Bug Hunting 1 N module scanners Continuous (rescans on new code)
Test Infra Improvement 1 N improvers Continuous (periodic analysis)
Architecture Design 1 — Continuous (monitors spec needs)
Epic Planning 1 — Continuous (monitors milestone planning)
Human Liaison 1 — Continuous (never exits)
Agent Evolver 1 — Continuous (periodic analysis)
Architecture Guard 1 — Continuous (periodic scans)
Spec Evolution 1 — Continuous (monitors merged PRs)
Backlog Grooming 1 — Continuous (periodic quality checks)
Documentation 1 — Continuous (monitors milestones)
Timeline Updates 1 — Continuous (daily minimum)
Project Owner/Triage 1 — Continuous (strategic priorities)
System Watchdog 1 dispatches one-offs Continuous (5-min audit cycle)
Stream Category Supervisors Internal Workers Tier Lifecycle
──────────────────────── ─────────── ─────────────────── ───────── ──────────────
Implementation 1 N_FULL workers Full Continuous (polls for new issues)
PR Review 1 N_HALF reviewers Half Continuous (polls for new PRs)
UAT Testing 1 N_QUARTER testers Quarter Continuous (retests on new code)
Bug Hunting 1 N_QUARTER scanners Quarter Continuous (rescans on new code)
Test Infra Improvement 1 N_QUARTER improvers Quarter Continuous (periodic analysis)
Architecture Design 1 — Singleton Continuous (monitors spec needs)
Epic Planning 1 — Singleton Continuous (monitors milestone planning)
Human Liaison 1 — Singleton Continuous (never exits)
Agent Evolver 1 — Singleton Continuous (periodic analysis)
Architecture Guard 1 — Singleton Continuous (periodic scans)
Spec Evolution 1 — Singleton Continuous (monitors merged PRs)
Backlog Grooming 1 — Singleton Continuous (periodic quality checks)
Documentation 1 — Singleton Continuous (monitors milestones)
Timeline Updates 1 — Singleton Continuous (daily minimum)
Project Owner/Triage 1 — Singleton Continuous (strategic priorities)
System Watchdog 1 dispatches one-offs Singleton Continuous (5-min audit cycle)
Total supervisors: 16 (each managing N workers where applicable)
Total concurrent workers: ~5N + ~11 singletons + one-off fixers
With N=4: ~31+ concurrent agents
With N=8: ~51+ concurrent agents
With N=16: ~91+ concurrent agents
Total supervisors: 16
Worker formula: N_FULL + N_HALF + 3×N_QUARTER + 11 singletons + one-off fixers
With N=4: 4 + 2 + 3×1 + 11 = 20 concurrent agents
With N=8: 8 + 4 + 3×2 + 11 = 29 concurrent agents
With N=16: 16 + 8 + 3×4 + 11 = 47 concurrent agents
```
Supervisors use `bash sleep` for genuine blocking waits between polling
@@ -530,32 +552,32 @@ launch_supervisor("issue-implementor", "implementor-pool",
"You are the implementation pool supervisor.
Repo: <owner>/<repo>. Forgejo PAT: <PAT>.
Git: <name> <email>. Username: <username>.
Max parallel workers: N.
Max parallel workers: N_FULL.
Milestone filter: all milestones.")
launch_supervisor("ca-continuous-pr-reviewer", "reviewer-pool",
"You are the PR review pool supervisor.
Repo: <owner>/<repo>. Instance ID: reviewer-pool-1.
Forgejo PAT: <PAT>. Git: <name> <email>. Username: <username>.
Max workers: N.")
Max workers: N_HALF.")
launch_supervisor("ca-uat-tester", "tester-pool",
"You are the UAT testing pool supervisor.
Repo: <owner>/<repo>. Instance ID: uat-pool-1.
Forgejo PAT: <PAT>. Git: <name> <email>. Username: <username>.
max_workers: N.")
max_workers: N_QUARTER.")
launch_supervisor("ca-bug-hunter", "hunter-pool",
"You are the bug hunting pool supervisor.
Repo: <owner>/<repo>. Instance ID: hunter-pool-1.
Forgejo PAT: <PAT>. Git: <name> <email>. Username: <username>.
max_workers: N.")
max_workers: N_QUARTER.")
launch_supervisor("ca-test-infra-improver", "test-infra-pool",
"You are the test infrastructure improvement pool supervisor.
Repo: <owner>/<repo>. Instance ID: test-infra-pool-1.
Forgejo PAT: <PAT>. Git: <name> <email>. Username: <username>.
max_workers: N.")
max_workers: N_QUARTER.")
launch_supervisor("ca-architect", "architect",
"You are the continuous architecture designer.
@@ -566,8 +588,7 @@ launch_supervisor("ca-architect", "architect",
launch_supervisor("ca-epic-planner", "epic-planner",
"You are the continuous epic planner.
Repo: <owner>/<repo>. Instance ID: epic-planner-1.
Forgejo PAT: <PAT>. Git: <name> <email>. Username: <username>.
max_workers: N.")
Forgejo PAT: <PAT>. Git: <name> <email>. Username: <username>.")
launch_supervisor("ca-human-liaison", "human-liaison",
"You are the human liaison.
@@ -637,8 +658,12 @@ invoke ca-session-persister with:
checkpoint: "Phase C.2: ALL 16 supervisors launched via prompt_async.
Watchdog entering monitoring loop.
Session IDs recorded in /tmp/ca-supervisor-sessions.env.
Pool supervisors (N workers each): implementor, reviewer,
tester, hunter, test-infra-improver.
Tiered pool supervisors:
implementor (N_FULL=<N_FULL> workers),
reviewer (N_HALF=<N_HALF> workers),
tester (N_QUARTER=<N_QUARTER> workers),
hunter (N_QUARTER=<N_QUARTER> workers),
test-infra (N_QUARTER=<N_QUARTER> workers).
Singleton supervisors: architect, epic-planner, human-liaison,
agent-evolver, arch-guard, spec-updater, backlog-groomer,
docs-writer, timeline-updater, project-owner, system-watchdog."