What you are proving
That a single autopilot line can take a legacy codebase and autonomously drive a complete, council-reviewed in-place framework upgrade — and, just as importantly, that the built-in Risk Gate and review loop keep a human in control and refuse to declare success until the findings are actually zero. Unlike the Migration Autopilot walkthrough, which stopped at the gate and escalated, this run shows the full closed loop: gate → conditional approval → implement → review → remediate → clean re-review → Go. The squad derived the whole Research → Council → Plan → Implement → Review pipeline itself.
| Capability | Squad member (role) | Notes |
|---|---|---|
| Upgrade-path research | Alpha (researcher) | Dependency & compatibility assessment; three blockers — non-SDK csproj, MSTest v1/GAC, dotnet CLI runbook. |
| Modernization planning | Beta (lead), Epsilon (modernizer) | Sequenced the SDK conversion, test-stack swap, and config cleanup with gate criteria. |
| Council (arch, security, RAI) | Zeta, Eta, Theta (architect, security, rai) | Go-With-Conditions; Security flagged High Risk and fired the Risk Gate. |
| In-place upgrade | Gamma (developer) | SDK-style .csproj, net10.0, NuGet MSTest, dotnet CLI + global.json pinning. |
| Quality review + gate | Delta (tester) | The star of this demo — found workflow gaps, then re-reviewed the fixes to zero. |
Before you start
This demo runs against a prepared repository, hve-squad-modernize-dotnet — the
Legacy Inventory Manager, a small app that is intentionally legacy:
a class library, a console front-end, and 20 MSTest unit tests, all starting on
.NET Framework 4.8. The whole run edits the repo in place; there is
no cloud and no spend, so it is safe to run live.
| Prerequisite | Why | Check |
|---|---|---|
| hve-squad installed | The modernization cast — researcher, lead, modernizer, developer, tester, architect, security, RAI — is dispatched by the coordinator. | apm install "Peter-N91/hve-squad" |
| VS Code + Copilot (agent mode) | The coordinator dispatches the cast as subagents. | — |
The hve-squad-modernize-dotnet repo | Holds the legacy .NET Framework 4.8 solution (Core, ConsoleApp, Tests). | Open it as the workspace. |
| .NET 10 SDK | Needed for the in-place upgrade to build and run the modernized net10.0 projects. | dotnet --version |
In place, not a rewrite. The squad upgrades the existing solution — same
domain models, same tests, same behavior — it does not scaffold a new app. That is the
point: modernization you could hand to a maintainer, with every change owned by a named
member and persisted as decisions and history under .copilot-tracking/squad/.
The one request
The entire demo is this single autopilot line. It names the outcome, not the steps — the squad sequences the pipeline itself:
/squad mode=autopilot request="Modernize this repository from .NET Framework 4.8 to .NET 10. Assess the current projects and dependencies, define the target state, and carry out the in-place upgrade end-to-end."
Narrate: "One line, no babysitting. Autopilot runs Research → Council → Plan → Implement → Review, stops only where risk demands a human, and won't claim success until the findings are zero."
Where it self-escalated first
Early on, the researcher (Alpha) reported it was missing the delegation tooling it needed and paused the pipeline rather than guessing. The human approved a roster override — the Squad Modernization Planner took over the research duties — and the run resumed. It is a small moment, but it is the safety story in miniature: the squad stops and asks instead of forcing a bad path.
What autopilot produced (Research → Council)
Research completed with a conditional Go, then a pre-implementation council assessed the upgrade from three angles before any code changed:
| Stage | Owner(s) | Output | Status |
|---|---|---|---|
| 1 · Research | Alpha | Dependency & compatibility findings; blockers B1 non-SDK csproj, B2 MSTest v1/GAC, B3 framework-specific App.config, B4 VS-path-dependent build. | ✅ Go (conditional) |
| 2 · Council | Zeta, Eta, Theta | Architecture (test-platform discontinuity, build/config drift), Security (High Risk: missing SAST+SCA, undefined dependency-trust policy), RAI (non-material). | ✅ Go-With-Conditions |
| 3 · Risk Gate | Human | Security High Risk fired the gate — approved with conditions in advisory strictness mode. | ✅ Approved |
| 4 · Implement | Gamma, Epsilon | SDK-style conversion, NuGet MSTest, App.config cleanup, dotnet CLI workflows, global.json pinning. | ✅ Complete |
| 5 · Review | Delta | Validation + remediation loop. | ✅ Go (after remediation) |
| 6 · Validate | — | Final-outcome validation. | ⏸ Awaiting user (Promote-to-RC) |
The Risk Gate — where it stopped for a human
The council verdict was unanimous Go-With-Conditions, but Security (Eta) rated the work High Risk and named two hard blockers, which fired the Risk Gate. Autopilot did not push past it — it paused and handed the decision to the human:
| Role | Verdict | Key conditions |
|---|---|---|
| Architecture (Zeta) | Go-With-Conditions | Document the test-platform migration; add a build-contract stability plan; make the config-modernization strategy explicit. |
| Security (Eta) | Go-With-Conditions · High Risk | Add a SAST + SCA scanning workflow and a defined dependency-trust policy before modernized code merges. |
| RAI (Theta) | Go-With-Conditions | Non-material scope; keep review/quality gates and audit traceability intact. |
The human chose Approve-With-Conditions in advisory strictness mode: the pipeline resumes, the conditions ride along into the plan, and non-critical issues are logged and tracked rather than silently ignored. The squad never picks for you at a risk gate.
What the upgrade actually changed
With the gate cleared, the developer (Gamma) and modernizer (Epsilon) carried out the in-place upgrade — resolving every research blocker:
| Blocker | Before | After |
|---|---|---|
| Project format | Legacy non-SDK .csproj, .NET Framework 4.8 | SDK-style .csproj targeting net10.0 |
| Test stack | MSTest v1 wired through the GAC | NuGet MSTest (Microsoft.NET.Test.Sdk, MSTest.TestFramework, MSTest.TestAdapter) |
| Build & test | Visual Studio path-dependent | dotnet CLI with SDK pinned in global.json |
| App config | Framework-specific App.config metadata | Stale config removed |
| CI / security | None | dotnet-ci.yml + security-scanning.yml (SAST + SCA) added |
Independent validation reported a clean dotnet restore, Debug and Release builds,
and 20/20 tests passing — same tests, same behavior, new framework. The
analyzer / nullability hardening (B5) was deferred by design and tracked as a
follow-on, not silently dropped.
The review loop — where it proved the work
This is the payoff. The first review (Delta) passed the build but did not wave the work through — it found three real issues and sent the work back:
| # | Finding | Severity | Why it matters |
|---|---|---|---|
| 1 | CodeQL job can drift to the runner's preinstalled SDK | Medium | Security scan wasn't pinned to global.json, so it could validate a different SDK than CI. |
| 2 | CI triggers only on PR + manual dispatch | Medium | Direct pushes to main or merge-queue edges could bypass CI entirely. |
| 3 | Empty App.config still included | Low | Harmless at runtime, but ambiguous for maintainers. |
The squad ran a remediation loop: pinned the CodeQL SDK via
actions/setup-dotnet with global.json, added a push
trigger for main, and removed the empty App.config include. The
re-review came back 0 Critical · 0 High · 0 Medium · 0 Low with 20/20 tests
still green — verdict Go.
This is the whole point of the demo. A model that just generated code would have handed over a green build and called it done. The squad reviewed its own work, named three concrete gaps with file and line, fixed them, and re-proved the result to zero findings before claiming success — with a human approving the risk gate along the way.
The decision point
With a clean Go verdict, the run halts at final-outcome validation and lets the human choose — it never promotes for you:
- Promote-to-RC (recommended) — accept the Go verdict and tag the code as a release candidate for final signoff.
- Request-Changes — send it back into Implement → Review for more work.
- Stop — halt the run; the code stays as-is.
The whole run took 8 turns across 11 dispatches for roughly
$0.72 (~72 AI credits), with two human interventions — the researcher override
and the risk-gate approval — every decision persisted under
.copilot-tracking/squad/.
Failure-safe fallbacks
| If… | Then… |
|---|---|
| A role reports missing tooling | That is the self-escalation story — the squad pauses and asks for a roster override rather than forcing a bad path. Show the decision log entry. |
| The .NET 10 SDK is not installed | Research, council, and planning still run; only the live build/test needs the SDK. Show global.json pinning instead. |
| Review comes back clean on the first pass | Point at the review artifact anyway — the remediation loop is the differentiator; describe the findings it would have caught. |
| Someone asks "just upgrade it and ship" | The squad still runs the Risk Gate and review loop — it never skips the gate or claims success past open findings. |
Closing talking points
- One request, full pipeline. A single autopilot line drove Research → Council → Plan → Implement → Review with no per-step prompting.
- In-place modernization, not a rewrite. The legacy solution moved from .NET Framework 4.8 to .NET 10 with the same tests passing — 20/20, before and after.
- The gate and the loop are the product. Security fired a Risk Gate a human approved, then review found three gaps and the squad remediated to zero findings before Go.
- You stay in control. Two human decisions — a roster override and the risk-gate approval — and every choice persisted as decisions and history.