Date: May 18, 2026 Sources: CODE_REVIEW_ANALYSIS.md, sandboxed.sh research, live testing session
ListLabelsreturnedID: 0for all labels (root cause of most label bugs)RemoveIssueLabelsent name string instead of numeric ID- Scheduler
addLabel/removeLabelsent name strings instead of IDs EnsureLabelscreated duplicates on every call (Forgejo allows duplicate names)forgejo_create_issueaddedblockedas string["blocked"]instead of{"labels": [id]}AddIssueLabelsCreateLabelfallback created duplicates- FSM:
needs-role→openedtransition rejected - FSM:
ready→plan-approvedtransition missing - FSM:
blocked→plan-approvedtransition missing - FSM: state got stuck on invalid transitions (now always updates to actual labels)
- Green-light detection (plan-approved/ready/implementing) now triggers sessions
- Green-light events skip role gate + scaffold detection
- Role gate had two redundant blocks; both now skip green-light events
handleRoleAssignmentreturns bool so green-light check runs afterrole:*labels added toEnsureLabels- Protected branch
git commitblocking (confirmed FIXED in review)
Critical bugs, data races, coordination gaps, and architectural improvements remain.
Status: Still exists
Impact: HasConflicts always false; forgejo_merge_pr proceeds on conflicting PRs
Fix: has_conflits → has_conflicts
Effort: 1 min + verify with Forgejo API swagger spec
Status: Still exists
Impact: Any API timeout/503 disables the merge gate; PRs proceed without conflict checking
Fix: Change return false, "", nil → return true, "Merge gate unavailable: ...", nil
Effort: 10 min
Status: Still exists
Impact: Go race detector violation; stale reads under concurrent session access
Fix: Read LastActive under sess.mu.Lock() in both reapIdle and evictOldest
Effort: 20 min
Status: Still exists Impact: Wastes retry budget on unrecoverable state; 3s delay Fix: Return immediately on 409; only retry on 405 Effort: 2 min
Status: Still exists
Impact: Lease check may fail on some git versions
Fix: Use explicit refspec: HEAD:refs/heads/<branch>
Effort: 5 min
Status: Still exists Impact: Config says 60min, runtime fallback is 30min Fix: Remove hard-coded fallback; rely on config validation Effort: 5 min
Status: Still exists
Impact: Redundant EnsureLabels calls under concurrent events (idempotent but wasteful)
Fix: Replace Load+Store with LoadOrStore
Effort: 5 min
Status: Not implemented
Impact: database is locked errors under concurrent sessions
Fix: Add PRAGMA busy_timeout = 5000; PRAGMA journal_mode = WAL in all schema init
Effort: 30 min
Status: Not implemented
Impact: Callers can't detect specific failures (ErrMaxTurnsReached, ErrSessionTimeout, etc.)
Fix: Add internal/sentinel/ package with typed errors; use errors.Is() throughout
Effort: 2 hrs
Status: Still exists
Impact: 100-500ms latency added to every turn for automerge label check
Fix: Cache hasAutomerge in Agent struct; detect on first turn only
Effort: 1 hr
Status: Still exists Impact: Large PR diffs silently dropped from context with no visibility Fix: Log when truncation occurs; include first N chars even when full payload dropped Effort: 30 min
Problem: Implementers working on sub-issues #3-#6 from the same parent have zero shared context. Each sees only its own issue body. This causes duplication, inconsistency, and conflicting approaches. Fix:
- When
buildContextdetectsDepends on: #Nin the issue body, fetch parent issue (#N) body + comments - Add
forgejo_get_sibling_issuestool that returns sibling issue bodies and PR status - Include parent body excerpt in
forgejo_create_issuetool output Effort: 4 hrs
Problem: Two implementers can both start on the same ready issue. No lock, no claim, duplicate PRs.
Fix:
- Add
in_progressFSM state and label - When an implementer session starts, atomically: remove
ready, addin_progress - Other implementers see
in_progresslabel and skip - On session timeout/failure, remove
in_progress, re-addreadyEffort: 3 hrs
Problem: Only bot-created PRs trigger auto-reviewer. Human PRs sit unreviewed.
Fix: On every pull_request.opened, spawn reviewer session regardless of author. Keep bot-auto-bypass for merge approval.
Effort: 2 hrs
Problem: PM creates sub-issues but the implementer sees none of the PM's analysis.
Fix: When forgejo_create_issue creates a sub-issue, append parent body excerpt to sub-issue body: \n\n## Parent Context (from #N)\n{parent_body_excerpt}
Effort: 1 hr
Problem: Mutual Depends on: #N creates permanent deadlock.
Fix: Before evaluating dependencies in OnPRMerged, build adjacency graph and detect cycles. Post warning comment on affected issues if cycle found.
Effort: 3 hrs
Problem: When 5 sub-issues are unblocked simultaneously, all get ready at once, causing merge conflicts.
Fix: Parse Priority: N syntax from issue bodies. Scheduler unblocks one at a time in ascending priority. Without explicit priority, use issue number order.
Effort: 4 hrs
Problem: PM creates sub-issues then stops. No mechanism detects when ALL children are done. Fix: On every PR merge, check if the merged PR's issue has a parent. If all children of that parent are closed, post a completion comment on the parent and close it. Effort: 3 hrs
Problem: Sessions stuck in blocked or working with no progress may never be cleaned up.
Fix: Background goroutine (every 30 min) scans issueStates for sessions that: have been in_progress > 2hrs with no recent turn logs, or have been blocked > 6hrs. Posts nudge comments or transitions to failed:timeout.
Effort: 4 hrs
Problem: Recovery only runs on startup with 2hr window. Sessions idle overnight are lost. Fix: Extend window to 24hrs. Add periodic recovery runner (every 1hr while running). Effort: 1 hr
Problem: Four identical copies across forgejo/client.go, forgejo_tools.go, mergequeue/queue.go, scheduler/scheduler.go.
Fix: Move to internal/forgejo/util.go, export, remove all local copies.
Effort: 20 min
Problem: isIssueClosed assumes "not closed" on any API error, keeping issues blocked indefinitely.
Fix: Retry 2-3 times with exponential backoff before assuming not-closed. Schedule deferred re-check via timer if all retries fail.
Effort: 2 hrs
Problem: .. traversal in read_file/write_file not explicitly tested.
Fix: Add test cases: repo/../../../etc/passwd, ../../../etc/shadow. Consider filepath.Rel as defense-in-depth.
Effort: 30 min
Problem: No test for 10 simultaneous webhook events on the same repo. Fix: New integration test that fires 10 issues simultaneously, verifies all sessions created, no duplicates, no data races. Effort: 4 hrs
Problem: CreateLabel fallback silently swallows non-422 errors.
Fix: Return error if label creation fails with status other than 422.
Effort: 15 min
Problem: Fordjent spawns new LLM calls per turn. Long-running bash commands (npm install, go test ./...) die between turns because the process exits.
Solution: Keep a persistent CLI process per session with open stdin. Agent sends commands via stdin, reads output asynchronously. This survives across turns.
Effort: 8 hrs (major architectural change)
Problem: FSM prompts, role instructions, tool descriptions, and agent behaviors are hardcoded in Go. Any change requires a rebuild and redeploy.
Solution: Externalize agent configuration to a Forgejo repo (e.g., fjadmin/fordjent-config). On session start, clone/pull the config repo. Prompts, skill instructions, tool descriptions loaded from YAML/markdown files. Changes reviewed via PR. Hot-reload on push webhook.
Effort: 10 hrs
Problem: When a provider times out (429, 503, context deadline exceeded), Fordjent retries the same provider. If the provider is down, the session fails.
Solution: In provider/client.go, accept a list of providers per role. On non-retryable failure after max retries, try the next provider in the chain. Config:
role_providers:
implementer:
- "wafer-qwen"
- "ollama-cloud"
reviewer:
- "wafer-glm"
- "kimi-k2.6"Effort: 4 hrs
Problem: Fordjent uses a single Docker image. Every session on a Go project burns tokens running go mod download. Sessions on Node.js projects fail because npm isn't installed.
Solution: Detect project type from file presence (go.mod → Go template, package.json → Node template). Templates specify base image, pre-installed packages, and init scripts. Docker compose starts per-template containers.
Effort: 8 hrs (requires Dockerfile changes, new template config)
Problem: Fordjent's bash tool runs with full container access. Prompt injection could write to ~/.bashrc, exfiltrate keys, or access other sessions.
Solution: Add bubblewrap inside the Docker container. Every bash execution runs in a new user namespace with:
- Filesystem: bind-mount only
repoDir/as read-write, everything else read-only or inaccessible - Network: proxy through allowlisted domains only (Forgejo API, LLM endpoints)
- No access to
/var/lib/fordjent/work/(other sessions) Effort: 6 hrs
Problem: Only /status (polling) and raw JSONL logs. No real-time visibility into agent progress.
Solution: Add GET /stream?session_key=X endpoint that pushes SSE events: status, thinking, tool_call, tool_result, assistant_message, error. Separate transcript (user-facing) from trace (tool execution) from debug (protocol noise).
Effort: 4 hrs
Problem: Forgejo tokens, API keys in plaintext .env. No encryption at rest.
Solution: AES-256-GCM encrypted secrets file. Key derived from environment variable. Decrypt at startup. Optionally: Forgejo-backed secrets via fjadmin/fordjent-secrets private repo.
Effort: 3 hrs
Problem: PM creates sub-issues then exits. Cannot answer implementer questions or revise decomposition.
Fix: PM sessions persist in "waiting" state with 24hr idle timeout. On sub-issue completion or comment from implementer, PM session re-activates. PM tool set includes forgejo_get_sub_issues and forgejo_summarize_completion.
Effort: 6 hrs
Problem: Implementer has no way to ask the PM clarifying questions.
Fix: forgejo_ping_parent tool that posts a comment on the parent issue with @fordjent-bot mention. This triggers PM session re-activation.
Effort: 2 hrs
Problem: Reviewer sees PR code but not the parent issue's overall requirements.
Fix: If PR body contains Closes: #N or Fixes: #N, fetch the parent issue body + comments and include in reviewer buildContext.
Effort: 2 hrs
Problem: Only title tags and role:* labels are checked. Issue body content ignored.
Fix: detectRoleFromIssue also scans issue body for role keywords. Fallback only when both title and body have no role hints.
Effort: 1 hr
Problem: Issues with ready label but no active session sit forever.
Fix: Periodic goroutine (every 5 min) scans for open issues with ready label and no active session. Creates sessions for any found.
Effort: 2 hrs
Phase 0 (today, 1 hr)
└─ fix 3 critical safety bugs
Phase 1 (today, 3 hrs)
└─ fix 8 high-priority bugs
Phase 2 (this week, 12-20 hrs)
└─ coordination architecture (context sharing, claim protocol, reviewer coverage)
Phase 3 (next week, 8-12 hrs)
└─ production hardening (dedup, concurrency tests, retry hardening)
Phase 4 (next sprint, 15-25 hrs)
└─ sandboxed.sh-inspired features (persistent sessions, config library, sandboxing)
Phase 5 (future sprint, 8-15 hrs)
└─ complete multi-role workflow (PM re-activation, feedback channels, background scanning)
| Phase | Items | Effort |
|---|---|---|
| 0 — Critical | 3 | 1 hr |
| 1 — High | 8 | 3 hrs |
| 2 — Coordination | 9 | 12-20 hrs |
| 3 — Hardening | 5 | 8-12 hrs |
| 4 — sandboxed.sh | 7 | 15-25 hrs |
| 5 — Multi-role | 5 | 8-15 hrs |
| Total | 37 | 47-76 hrs |
Plan generated from: CODE_REVIEW_ANALYSIS.md (4-agent parallel review), sandboxed.sh research, and live testing session on May 13-18, 2026.