Skip to content

feat(autopilot): each ticket runs as a Microsoft Agent Framework workflow - #270

Merged
hoangsnowy merged 1 commit into
mainfrom
feat/maf-ticket-workflow
Oct 23, 2026
Merged

hoangsnowy merged 1 commit into
mainfrom
feat/maf-ticket-workflow

Conversation

@hoangsnowy

Copy link
Copy Markdown
Owner

Summary

"MAF controls the agents" — for real now, on the path that builds VNChessAcademy.

The Autopilot Orchestrator agent decides which ticket starts; a Microsoft Agent Framework Workflow (TicketWorkflow, MAF 1.25 WorkflowBuilder + conditional edges, InProcessExecution) then runs that ticket's whole flow:

Code ─► Checks ─(red / conflicts, try<3)─► Code        (behind its base → updated in place)
           └─(green)─► Review ─(changes, try<3)─► Code
                          └─(approved)─► Test ─(failed, try<3)─► Code
                                            └─(passed)─► Merge (Build-and-merge) / ready for a person
  • Steps are the existing agents (ITicketSteps → BoardTicketSteps over BoardTaskService): scoped autonomy, Insights metrics, PR evidence unchanged.
  • TicketWorkflowRunner: one workflow per ticket; while it runs Autopilot counts it as a running slot and leaves it alone; its trail goes to the Autopilot log. Out of rounds → blocked for a person (Orchestrator may retry/ask); agent couldn't run or restart → step-by-step path continues.
  • BoardTaskService.Begin{Start,Review,Test}Async return the running work; the one-acceptance-run-at-a-time slot is held by the Testing step for both paths.
  • Settings › Autopilot › Each ticket runs as: MAF workflow (default) / Step by step.
  • Fixes code-scanning #337 (nullable ticket numbers).

Test plan

  • TicketWorkflowTests (9) run the real MAF engine against scripted steps: green path, red checks, conflicts, behind base, requested changes + failed acceptance, 3-round cap → needs a person, coding couldn't finish, checks timeout, no auto-merge → ready for a person.
  • Full suite green (1611).
  • Lab: next started ticket logs "a MAF workflow runs it" and ends with "#N · MAF workflow: merged (…)".

🤖 Generated with Claude Code

https://claude.ai/code/session_018WAdQ7Rm24xss5QDSvXtJB

…flow

The Autopilot Orchestrator agent decides which ticket starts; a MAF Workflow (TicketWorkflow) then runs that ticket's
whole agent flow — Coding → checks → Reviewer → Testing → merge — with conditional edges back to the Coding agent for
red checks, conflicts, requested changes and failed acceptance (the rules' 3 rounds), and a branch behind its base
updated in place. Each step is an existing agent (ITicketSteps → BoardTicketSteps over BoardTaskService), so scoped
autonomy, Insights metrics and evidence on the PR are unchanged.

- TicketWorkflowRunner hosts one workflow per ticket; while it runs, Autopilot counts the task as a running slot and
  leaves it alone. Its trail goes to the Autopilot log ("#41 · MAF workflow: merged (coded → checks green → …)").
  Out of rounds → the changes are blocked for a person (the Orchestrator agent may retry or ask); an agent that
  couldn't run, or a flow a restart cut short → the step-by-step path continues from where the task stands.
- BoardTaskService.Begin{Start,Review,Test}Async return the running work; one acceptance run at a time is now held
  by the Testing step itself, for both paths.
- Settings › Autopilot › "Each ticket runs as": MAF workflow (default) / Step by step.
- Also fixes code-scanning #337 (nullable ticket numbers read via patterns in the Orchestrator code).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018WAdQ7Rm24xss5QDSvXtJB
Comment on lines +193 to +196
foreach (var r in repos[s.Id].Where(r => r.Status is not "Failed"))
{
if (PrNumber(r.PrUrl) is { } pr) { current.TryAdd((r.Owner, r.Repo, issue), (pr, r)); }
}
var openTickets = planTickets.Where(t => t.Open).Select(t => t.Number).ToHashSet();
var titles = tickets.Where(t => t.Number is not null).GroupBy(t => t.Number!.Value).ToDictionary(g => g.Key, g => g.First().Title);
var titles = new Dictionary<int, string>();
foreach (var t in tickets) { if (t.Number is { } number) { titles.TryAdd(number, t.Title); } }
@hoangsnowy
hoangsnowy merged commit e32fffa into main Oct 23, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants