AWS made its .NET modernization capability generally available through the command line on September 9, 2026. The AWS Transform for .NET CLI announcement matters because it moves an agentic transformation from a guided interface into a scriptable execution surface. That is useful for repeatable assessments and portfolio work, but it also makes a bad assumption repeatable. A command can modify hundreds of files faster than a review team can understand why those files changed.
The correct operating model is therefore not "run the tool and fix whatever fails." It is to treat every generated commit as an untrusted migration proposal. Freeze a known input, record the tool and transformation versions, capture an independent behavior baseline, inspect the proposed plan, classify every diff, and make human acceptance visible in source control. A zero-error build proves that a compiler accepted one configuration. It does not prove that authentication still authorizes the same users, serializers emit the same contracts, transactions commit at the same boundary, Windows integrations still work, or production deployment behaves the same way.
Broader coverage of AI-assisted software engineering explains why these tools are becoming normal. This playbook addresses the harder operational question: how to let the AWS Transform .NET CLI accelerate mechanical work without delegating application meaning, release authority, or recovery decisions. The result should be a modernization that an owner can explain, test, approve, observe, reverse, and audit months after the generated code first appeared.
1. Define the Modernization Decision and Non-Negotiable Outcomes
Start with the production decision, not the tool. The decision is usually narrower than "modernize the application." It may be to remove an unsupported .NET Framework dependency, make a service deployable on a supported runtime, reduce Windows-only hosting, or create a maintainable path to .NET 8 or .NET 10. Write the intended target state in terms that an application owner, security reviewer, operations team, and business process owner can all test.
The modernization charter should identify business outcomes that cannot change without a separate design decision. Examples include who can sign in, how tenant boundaries are enforced, which fields appear in an external payload, when money or inventory becomes committed, where files are written, and what happens when a downstream system times out. Current software development trends make automation easier to adopt, but speed is not an acceptance criterion. The organization still owns the semantics.
Evidence area | Non-negotiable question | Acceptance owner |
Business behavior | Do the same approved inputs produce materially equivalent business results? | Application owner |
Security | Are authentication, authorization, secrets, cryptography, and audit controls at least as strong? | Security reviewer |
Operations | Can the target be deployed, observed, recovered, and rolled back inside agreed objectives? | Platform or SRE owner |
Engineering | Are generated changes understandable, reproducible, testable, and maintainable? | Code owners |
Define the first stop condition here: if the team cannot name the behaviors that must remain stable, do not transform production-bound code. Assessment can continue, but acceptance cannot. A tool-generated change becomes engineer-authored acceptance only when named reviewers attest that the evidence supports the intended outcome.
2. Inventory the .NET Estate Before Running the Tool
Repository discovery is a dependency exercise, not a file count. One solution can call COM components, read machine-level configuration, depend on a shared database, load private NuGet packages, invoke scheduled tasks, or assume an IIS identity. Build an estate inventory that connects source code to runtime behavior before selecting the first candidate.
2.1 Classify Frameworks, Project Types, and Windows Dependencies
For each solution, record the current target framework, language, project type, SDK style, build toolchain, package sources, test frameworks, deployment model, and operating-system assumptions. Include projects that are not deployed independently, such as shared class libraries, installers, database migration utilities, and test harnesses. A repository that contains multiple solutions needs an explicit unit of work because the CLI operates against a local Git repository and the .NET transformation works at solution and project scope.
Inventory field | Examples | Why it changes the plan |
Runtime and language | .NET Framework 4.7.2, .NET Core 3.1, C#, VB.NET | Determines documented support, preview status, and target choices |
Project type | MVC, Web API, Web Forms, WCF, WinForms, WPF, test project | Separates supported paths from preview paths |
Windows coupling | Registry, Event Log, COM, GDI+, named pipes, Windows authentication | May preserve a Windows deployment even after the runtime changes |
External contracts | SOAP, JSON, XML, flat files, database schemas | Requires contract and consumer testing, not only unit tests |
Build inputs | Private feeds, generated code, certificates, licensed SDKs | May be unavailable to the transformation environment or CI worker |
Use Microsoft's .NET upgrade guidance to identify framework features, application models, package changes, and breaking changes that a compiler cannot resolve automatically. Search for P/Invoke, COM interop, System.Drawing, registry access, AppDomain behavior, remoting, workflow technologies, machine certificate stores, and file-system paths with drive letters. The result is a risk classification, not a promise that every match must be removed.
Do not label an application "cross-platform" merely because it targets modern .NET. A service can run on modern .NET and still be Windows-dependent by design. Make that a deliberate target state, then test and support it as such.
2.2 Map Owners, Business Flows, and Deployment Topology
Every high-risk behavior needs an owner who can recognize drift. Map each solution and project to its code owners, product owner, security approver, test owner, deployment owner, data owner, and on-call team. Also identify consumers that are outside the repository, including partner integrations, desktop clients, scheduled jobs, report generators, and direct database users.
Trace a small set of business flows end to end. For an order service, that could be sign-in, price calculation, order creation, payment authorization, inventory reservation, confirmation publishing, and reversal after failure. Record the services, queues, files, databases, identity providers, and Windows services crossed by each flow. This map tells reviewers where a generated API substitution might alter more than the file being edited.
Tier 1: externally visible, regulated, financial, safety-related, or identity-critical flows.
Tier 2: internal operational flows with recoverable but material business impact.
Tier 3: low-volume utilities, read-only tools, or components with limited downstream coupling.
Select the first modernization candidate from Tier 3 or a well-observed slice of Tier 2. Avoid using an undocumented Tier 1 monolith as the discovery mechanism for how the transformation behaves. The pilot should reveal process defects without creating a production incident.
3. Verify Supported, Preview, and Unsupported Transformation Paths
As of the September 14, 2026 verification date, the AWS .NET modernization support matrix lists .NET Framework 3.5 and later, .NET Core 3.1, and .NET 5 and later as source versions, with .NET 8 and .NET 10 as documented targets. It labels C# class libraries, console applications, ASP.NET MVC, SPA back ends, Web API, Web Forms, common unit-test projects, and WCF services as supported. WinForms, WPF, Xamarin, and VB.NET are preview paths, which means completeness can differ from supported project types. Repositories without a solution, Blazor UI components, and Win32 DLLs without compatible libraries are documented limitations or exclusions.
Support is a product boundary, not a production guarantee. A supported Web Forms project can still rely on Windows authentication, IIS configuration, session behavior, or private libraries that require redesign. A preview WPF project may compile while retaining Windows-only behavior, which may be acceptable if the approved target remains Windows. Unsupported components require an explicit disposition before execution: retain behind an interface, replace with a supported alternative, separate into another deployment, manually port, or stop.
Two first-party pages can appear inconsistent because they describe different experiences. The general .NET page says original repository branches are not modified and transformed code is written to a separate target branch, while the CLI-specific guide to working with the .NET agent states that the local CLI replaces files in the working copy. Neither page displays a public update date, so record the retrieval date and apply the more specific page to the CLI. In practice, assume the CLI working tree is mutable and create your own disposable clone and branch boundary.
There is also a target-language nuance. The canonical managed-transformations catalog describes AWS/dotnet-modernization as generally available and mentions a default net10.0 target with net8.0 or later support, while the main .NET support page explicitly names .NET 8 and .NET 10. Until both pages agree on another target, production governance should restrict choices to the targets explicitly named by the .NET support page. Record the exact target in the manifest rather than accepting a changing default.
The dated September 9, 2026 GA announcement should govern CLI availability; the live support matrix should govern project eligibility; and the CLI-specific agent page and command reference should govern execution behavior. This source-precedence rule belongs in the runbook so that a future documentation change does not silently alter the modernization contract.
4. Freeze Inputs, Tool Versions, Credentials, and Source Boundaries
Reproducibility starts before the first command. Pin the input commit, identify the solution, record the transformation definition and version, select the target framework explicitly, and preserve the environment facts needed to rebuild. A transformation that cannot be reproduced from recorded inputs is evidence of an uncontrolled process, even when the generated branch builds.
4.1 Create an Immutable Transformation Manifest
The manifest is a team-owned evidence record, not an invented AWS configuration schema. Store it outside the mutable working tree or commit it before transformation, then sign or protect it according to your release process. At minimum it must contain the repository commit, tested CLI version, transformation name and version, selected target, included solution, exclusions, build command, identity context, and generated commit hash.
manifest_version: 1
repository:
name: Northwind.Ordering
input_commit: 7db14d6612c2eaa9f9d4f6db91f834f42c285bc1
solution: Northwind.Ordering.sln
cli:
version: 3.5.0
transformation:
name: AWS/dotnet-modernization
version: recorded-from-registry
target_framework: net8.0
inputs:
build_command: dotnet build Northwind.Ordering.sln --configuration Release
private_packages_snapshot: nuget-lock-2026-09-14.json
exclusions:
- src/LegacyLabelPrinter
- tools/PartnerCertificateUtility
output:
generated_branch: modernization/net8-atx-pilot
generated_commit: 1a8cd93a432f4c764bb67e4103d0df75b5cc8174The AWS Transform CLI version history listed 3.5.0, released July 8, 2026, as the latest version on the verification date. Do not write "latest" in the manifest. Record the value returned by atx --version, preserve the installer provenance used by the build image, and decide whether a new CLI release invalidates an in-progress comparison. For regulated or high-risk systems, a version change should require a new reproducibility run before acceptance.
Also record the transformation version where the registry exposes one. The command reference supports --transformation-version; use that pin when the organization has validated a specific definition. If a managed definition cannot be pinned in the chosen workflow, capture the registry output and execution time, then treat repeatability as reduced and require a second independent review run.
4.2 Isolate Repositories, Branches, and Secrets
Run the CLI in a disposable clone created from the approved input commit. The service identity should be able to execute the named transformation and read only the source and package locations required for that repository. It should not have production deployment credentials, database write access, signing keys, or broad package-publishing rights. The AWS Transform getting-started guide documents Node.js 22 or later, Git, a valid Git repository, standard AWS credentials, region selection, and AWS managed policies for execution or management. Prefer the narrower execute policy for runners that do not administer transformations.
Do not pass long-lived access keys through a repository, configuration file, command history, or generated evidence bundle. Use short-lived credentials supplied by the CI identity mechanism, set an explicit AWS_PROFILE or region where appropriate, and prevent secrets from being copied into agent context, build logs, test fixtures, or diffs. Review AWS Transform identity and access management guidance when designing custom policies and resource scopes.
The workspace should have no route to production control planes. Give it read-only access to sanitized package sources and test dependencies, and use an isolated artifact repository for outputs. Rebuild the surrounding test environment from reproducible infrastructure as code rather than pointing the transformed binary at a shared hand-configured server. Isolation makes failure safe and makes evidence repeatable.
Create a clean clone at the frozen commit and verify git status is empty.
Create a dedicated modernization branch and tag the input commit.
Mount secrets only for the process that needs them, then revoke or rotate them after the run.
Block direct pushes to protected branches and require code-owner review for generated commits.
Archive the manifest, CLI output, reports, build logs, and checksums in an immutable evidence store.
5. Capture the Pre-Transformation Build and Behavior Baseline
A post-transformation test run has no meaning without a trusted before state. AWS explicitly notes in its description of transformed-code testing that it can execute fully transformed unit-test projects after transformation but does not have access to pre-transformation results. Capture the baseline independently from the frozen input commit, in an environment whose toolchain and dependencies are recorded.
The baseline must include more than a test count. Save the exact build command, compiler warnings, package lock data, binary and container hashes, deployment manifest, configuration schema, test names and outcomes, code coverage, representative performance distributions, logs, external payloads, database effects, and recovery results. Where production data cannot be copied, create a deterministic corpus that preserves boundary conditions without exposing sensitive records.
Behavior area | Baseline evidence | Parity question |
Authentication and authorization | Successful and rejected principals, claims, roles, cookies or tokens, audit events | Are the same identities allowed and denied for the same reasons? |
Serialization | Golden JSON, XML, SOAP, message, and file samples including nulls and ordering where contractual | Are schemas, defaults, casing, dates, numbers, and errors compatible? |
Transactions | Commit, rollback, retry, timeout, and duplicate-delivery cases with resulting data state | Do boundaries and idempotency remain equivalent? |
Windows dependencies | Registry, COM, Event Log, certificate store, service account, IIS, WCF, and native library tests | Does each dependency still work, or has it been deliberately replaced? |
Paths and storage | Relative paths, UNC paths, long paths, permissions, temporary files, cleanup | Are path resolution and access controls unchanged or approved? |
Time and culture | UTC and local zones, daylight-saving transitions, locale parsing, decimal and date formatting | Do persisted and displayed values retain meaning? |
Deployment behavior | Startup, readiness, shutdown, config reload, scaling, health checks, rollback | Can operators deploy and recover within objectives? |
Make the baseline independently reviewable. A product owner should be able to see a business-result comparison without reading test framework output, while an engineer should be able to trace a difference to input data, code version, environment, and assertion. Keep baseline artifacts read-only after the transformation begins.
Set measurable gates before seeing the generated result. For example: all Tier 1 semantic tests must pass; no expected-deny authentication case may become allowed; contract snapshots must show no unapproved field or type change; p95 latency may regress by no more than 10 percent under the same load; error rate may not exceed the baseline confidence interval; and rollback must restore the previous build within the agreed recovery time. A gate written after a failure is an explanation, not a control.
6. Review the Assessment and Transformation Plan
The assessment and plan are approval artifacts. They should explain repository topology, project dependencies, package replacements, target framework choices, expected code groups, exclusions, and validation steps. The AWS transformation-plan workflow allows teams to review and customize the proposed plan; use that review to add business constraints, not merely to confirm that the tool found the projects.
Classify each plan item as mechanical, semantic, architectural, or unresolved. Mechanical work includes project-file conversion, namespace updates, and package version changes that preserve an agreed design. Semantic work can change runtime behavior, such as authentication middleware, serializer settings, transaction APIs, configuration loading, or hosting. Architectural work changes service boundaries, persistence strategy, messaging semantics, or deployment ownership and should become a separately designed work item. Unresolved work lacks a supported dependency or enough evidence to decide.
Plan class | Examples | Approval rule |
Mechanical | SDK-style project, compatible package update, API rename | Code owner reviews diff and tests |
Semantic | Auth pipeline, serializer, transaction, cache, file or time behavior | Domain owner and specialist approve evidence |
Architectural | Split service, replace protocol, redesign identity or data ownership | Architecture decision record and separate delivery plan |
Unresolved | Missing private package, unsupported library, unknown consumer | Stop affected project or exclude with documented boundary |
AWS documentation describes a bottom-up transformation that begins with low-level dependencies and can stop when a dependency cannot be ported. The official explanation of how .NET modernization works also describes package and API replacement, middleware and runtime configuration changes, IIS and WCF handling, and Linux-compatibility rewrites. Those are exactly the categories that require review because they can compile while changing behavior.
Approval of the plan authorizes a bounded experiment, not acceptance of future code. Record the approver, timestamp, plan checksum, accepted exclusions, and any steering document. If execution proposes a materially different dependency replacement or expands scope, pause and reapprove the plan.
7. Execute the CLI in a Controlled Workspace
First verify the installed binary and the available registry entries. The AWS Transform command reference is the governing source for command and flag syntax. Capture stdout, stderr, exit code, environment identifier, start and end times, and the Git state before and after each command.
atx --version
atx custom def list --json
atx custom def get -n AWS/dotnet-modernization --jsonBegin the first run interactively so reviewers can observe decision points and deny unexpected tool activity. The CLI-specific .NET page identifies AWS/dotnet-modernization as the managed transformation. Use an explicit repository path, an explicit build command, a bounded agent-minutes limit, and --do-not-learn when organizational policy requires opting out of lesson extraction.
atx custom def exec \
-n AWS/dotnet-modernization \
-p ./Northwind.Ordering \
-c "dotnet build Northwind.Ordering.sln --configuration Release" \
--limit 180 \
-dDo not add -x and -t merely to make the pipeline quiet. The AWS Transform workflow documentation says -x removes user assistance and -t trusts all tools, with the combination enabling full automation. It also warns that trust-all bypasses most security guardrails, and some prompt settings are not enforced in non-interactive mode. Treat that combination as privileged code execution inside the runner.
A controlled run has a narrow filesystem, no production credentials, an allowlisted network path, a resource budget, a timeout, and process-level logging. If the transformation attempts to access an excluded directory, install an unapproved tool, call an unexpected endpoint, or modify files outside the repository, terminate the job and preserve the workspace for review. Resume only after the cause is understood and the boundary is corrected.
After execution, do not normalize, format, or manually fix the generated branch before capturing it. Commit or identify the unmodified output first, calculate its hash, and update the manifest. Engineer-authored remediation should appear in later commits so reviewers can distinguish what the agent proposed from what the team deliberately changed.
8. Triage Generated Diffs by Semantic Risk
Diff review is not a file-count exercise. Divide the output by semantic risk, assign each class to a qualified owner, and review dependency changes before code that depends on them. A generated line is untrusted until its intent and effect are understood.
8.1 Review Dependencies, APIs, Configuration, and Security
Start with project files, package references, runtime identifiers, build targets, analyzers, and configuration. A package replacement can introduce a new serializer, HTTP stack, cryptography implementation, transitive license, native dependency, or default behavior. Compare lock files and dependency graphs, verify package provenance, scan known vulnerabilities, and confirm that private packages came from the approved source snapshot.
Then inspect API substitutions. Mechanical replacements are acceptable when the contract and runtime behavior are proven equivalent. An architectural substitution, such as replacing WCF transport, Windows authentication, remoting, or an unsupported workflow engine, is not a cleanup task. It needs an architecture decision, consumer plan, and independent tests. Apply backend development best practices to the maintained target, but do not use a modernization run to conceal unrelated refactoring.
Review configuration migrations for precedence, environment variable names, secret handling, connection-string parsing, logging levels, proxy behavior, certificate selection, and default ports. A move from web.config to modern configuration providers can change which value wins. Compare effective configuration at runtime without printing secret values.
Security review should follow data and control flow, not just scanner output. The OWASP Code Review Guide is useful for structuring review of authentication, authorization, session management, input validation, output encoding, error handling, cryptography, logging, and data protection. Examine new middleware order, permissive fallbacks, exception paths, and generated test changes. Reject any diff that weakens a security assertion to make the build pass.
Risk class | Northwind.Ordering example | Required review |
Low | Convert three class-library projects to SDK style and update compatible package versions | Project owner checks build metadata and package provenance |
Medium | Replace configuration access and update HTTP client construction | Platform owner tests precedence, proxy, timeout, and connection behavior |
High | Rewrite authentication middleware and JSON serializer options | Identity, API contract, and security owners approve semantic tests |
Critical | Change transaction flow around payment and inventory, or remove the label-printer integration | Business owner and architecture board approve, or stop the migration |
In the worked example, Northwind.Ordering.sln contains a Web API, domain library, data-access library, WCF partner adapter, MSTest project, and Windows label-printer utility. The utility is excluded because its vendor SDK has no compatible library. The WCF adapter is transformed only after a contract test proves SOAP compatibility. Generated changes to SDK-style projects are low risk, but serializer and authentication changes are high risk even when they touch fewer lines.
8.2 Review Authentication, Serialization, and Transaction Changes
Authentication review begins with the exact principal. Compare challenge and forbid behavior, cookie and token validation, claim type mapping, role evaluation, tenant context, clock skew, key rotation, logout, and audit events. Test anonymous, valid, expired, malformed, wrong-tenant, disabled, and insufficient-role cases. The acceptance criterion is not that a happy-path user can sign in; it is that every expected allow and expected deny remains correct.
Serialization review compares wire contracts byte-for-byte where consumers depend on that stability, then semantically where formatting differences are allowed. Check property naming, case sensitivity, null handling, enum representation, numeric precision, date and time-zone handling, reference loops, polymorphism, XML namespaces, SOAP actions, and exception payloads. Golden files should be versioned and reviewed by consumer owners rather than regenerated automatically after the migration.
Transaction review follows the unit of business work. Compare ambient and explicit transactions, isolation levels, connection enlistment, retries, distributed transaction assumptions, message publication order, outbox behavior, and rollback after partial failure. A generated change that replaces an unavailable transaction API can produce valid C# and still commit data earlier than before. Inject a failure after payment authorization but before inventory confirmation and verify that the resulting data, emitted messages, and retry behavior match the approved baseline.
The Northwind example exposes a critical drift: a transformed repository call saves an order before the integration event is staged, while the legacy path committed both through one transaction boundary. Unit tests still pass because they mock both components. The stop condition is immediate. Restore the generated branch to its captured commit, add a failing integration test that demonstrates the baseline boundary, and resolve the design in an engineer-authored commit. Do not ask the agent to keep iterating until a green test obscures the reason for the change.
Reject unexplained file or project deletions, especially tests, configuration, migrations, and deployment assets.
Reject reduced coverage or deleted assertions unless an owner approves a documented replacement.
Stop when an unsupported library is replaced without an approved contract and operational plan.
Stop when identical frozen inputs do not reproduce materially equivalent generated output or evidence.
Stop when business-result comparisons drift beyond the predeclared tolerance, even if the build is green.
9. Prove Tests, Performance, and Deployment Parity
Testing must prove the accepted target, not merely exercise the generated code. Run the frozen pre-transformation suite and the transformed suite against the same deterministic corpus. Preserve test identities so additions, removals, skips, retries, and changed assertions are visible. A post-transform pass rate cannot compensate for missing baseline tests.
Use layers. Unit tests protect local logic. Contract tests protect HTTP, SOAP, message, file, and database interfaces. Integration tests exercise real infrastructure substitutes and transaction boundaries. Security tests verify expected allow and deny outcomes, input handling, secret exposure, and dependency findings. Deployment tests prove startup, readiness, configuration, health, shutdown, rollback, and data compatibility. Broader guidance on automated security testing can inform the pipeline, but generated-code review remains a separate gate.
Gate | Measurable threshold | Failure action |
Build reproducibility | Two clean builds from the same commit produce the same dependency lock and functionally equivalent artifacts | Quarantine output and investigate toolchain or generated-input drift |
Semantic tests | 100% of Tier 1 cases pass; no expected deny becomes allow; no unapproved contract delta | Block merge and assign domain owner |
Coverage | No reduction in critical-path branch coverage; overall change within approved tolerance | Restore or replace tests before review continues |
Performance | p95 latency regression at most 10%; throughput and resource use within capacity budget | Profile, remediate, or reject target |
Deployment | Canary reaches readiness and processes synthetic flow; rollback meets RTO and data checks | Stop promotion and recover known supported build |
Performance comparisons need controlled load, stable data, warmed and cold-start scenarios, and distributions rather than a single average. Record CPU, memory, garbage collection, thread-pool behavior, connection pools, database calls, network timeouts, and startup time. Modern .NET may improve throughput while changing memory or concurrency characteristics that matter at scale.
Deployment parity must cover the actual target topology. Build the same package type that production will run, apply the same configuration precedence, use the same service identity shape, and validate probes and shutdown signals. If the modernization also changes from IIS to a container or from Windows to Linux, treat that as a combined application and platform migration with its own rollback. Do not let a successful local dotnet run stand in for deployment evidence.
Run at least one recovery drill with an ambiguous failure. For example, terminate the process after the database commit but before the response reaches the client. Confirm whether a retry duplicates the operation, whether idempotency keys survive, what the user sees, and how operators reconcile the result. Recovery evidence is part of behavioral equivalence because production systems fail between lines, not only at test boundaries.
Use the AWS transformation report as one evidence input. It can summarize file, package, API, build, and test outcomes, but it is not the acceptance record. The signed gate results, reviewer decisions, environment manifest, and production rehearsal evidence must be independently retained.
10. Integrate Modernization Into CI Without Auto-Merging
CI can make the process repeatable without making it self-authorizing. A modernization pipeline should create evidence and a reviewable branch or pull request, never merge to a protected branch or deploy to production. Separate the transformation identity from the merge identity and from the deployment identity. No single generated workflow should hold all three authorities.
Use an immutable input reference, pinned runner image, recorded CLI and transformation versions, scoped AWS credentials, locked package sources, and explicit limits. Store the manifest before execution. After the run, package the unmodified generated commit, CLI transcript, registry metadata, transformation report, dependency diff, test results, coverage, security findings, artifact hashes, and reviewer checklist as an evidence bundle.
Stage 1, assess: inventory and plan generation; no source changes accepted.
Stage 2, transform: run in isolated workspace and capture the pristine generated commit.
Stage 3, validate: build, semantic tests, security tests, performance checks, and deployment rehearsal.
Stage 4, review: code owners and specialist reviewers sign the risk-classified diff.
Stage 5, promote: a separate authorized workflow merges and deploys the approved commit.
Parallel work requires a merge policy. Freeze the modernization input while the generated branch is under initial review, or maintain a ledger of product commits that must be replayed. Rebase only after preserving the original generated commit and rerun affected gates. Never resolve a large conflict by choosing the generated side wholesale, because that can silently drop production fixes.
A second run from the same input can be valuable as a reproducibility check, but agentic output may not be byte-identical. Define what must be deterministic: selected projects, dependency decisions, risk classifications, behavior, and evidence. Materially different API or package choices from identical inputs are a stop condition until the variation is explained.
11. Handle Unsupported Libraries and Partial Transformations
An unsupported library is a planning decision, not a compilation nuisance. Classify it by business function, runtime criticality, source availability, vendor support, replacement options, data and protocol contract, and retirement timeline. Keep the unsupported component behind a stable boundary when possible, then modernize callers without pretending the whole system is portable.
Microsoft maintains a list of .NET Framework technologies unavailable on modern .NET. Use it with the AWS support matrix to identify remoting, application-domain, workflow, security, and other compatibility risks. A compatible NuGet package does not automatically reproduce operational behavior. Verify licensing, support status, patch cadence, native dependencies, and platform restrictions.
For Windows APIs that remain intentionally required, the Windows Compatibility Pack guidance can help identify supported compatibility surfaces. The decision is still architectural: retain Windows and document it, replace the API, isolate the dependency, or redesign the capability. Do not install a compatibility package simply to make warnings disappear.
Disposition | Use when | Control |
Retain | Supported modern .NET process still needs a Windows-only capability | Explicit Windows target, ownership, tests, and support plan |
Isolate | Dependency can remain behind a process or service boundary | Contract tests, failure handling, and separate deployment lifecycle |
Replace | Approved supported alternative preserves the required contract | Architecture decision and consumer validation |
Rewrite | Business value justifies a designed replacement | Separate project, scope, budget, and migration plan |
Stop | No safe, supported, or testable disposition exists | Do not accept partial transformation as production-ready |
Partial transformation can be a useful intermediate state if the boundary is explicit and independently deployable. It is unsafe when generated and legacy code share a database or transaction without a proven compatibility model. Record what remains, why it remains, who owns it, and the condition for completion or permanent retention.
12. Roll Out by Application Risk Ring
Promotion should expand evidence before it expands blast radius. Use application risk rings, not a calendar promise. A ring is entered only when its acceptance gates pass and exited only when defined production evidence remains stable for the observation window.
Ring | Scope | Required evidence |
0: laboratory | Disposable environment and deterministic test data | Reproducible build, diff classification, full semantic matrix, failure injection |
1: internal canary | Developers or internal users, no critical external writes | Deployment and rollback rehearsal, security review, live telemetry validation |
2: limited production | Small tenant, region, instance pool, or read-only flow | Business-result comparison, capacity margin, reconciliation and support readiness |
3: controlled expansion | Increasing share of representative traffic | Stable error, latency, authorization, contract, and transaction signals |
4: default | Primary production path with legacy fallback retained temporarily | Sustained objectives, completed recovery drill, decommission approval pending |
Select ring boundaries that prevent shared-state surprises. A 5 percent traffic canary is not isolated if both versions write incompatible schemas or compete for the same message. Prefer tenant, shard, region, or workload boundaries with clear routing and reconciliation. When write isolation is impossible, use shadow reads, compare-only execution, or a shorter blue-green cutover with rehearsed rollback.
Define promotion and stop signals in advance. Promotion might require zero authorization drift, zero unapproved contract differences, no duplicate or missing business events, p95 latency within tolerance, and no increase in support contacts. Stop on unexplained data divergence, retry storms, rising dead-letter volume, new Windows dependency failures, or an inability to reconcile results.
Each ring needs a named release commander, application owner, platform operator, security contact, and rollback authority. Avoid committee ambiguity during an incident. The person who can stop promotion should be identified before the canary starts.
13. Cut Over, Observe, and Recover Production Workloads
A cutover plan begins with the last safe decision point. Identify when traffic routing changes, when schemas become incompatible, when queued work crosses the boundary, and when the old build can no longer resume safely. Keep the known supported build, its configuration, its deployment artifact, and its infrastructure definition available until rollback criteria expire.
Observe semantics, not only infrastructure. Observability in deployment workflows provides the foundation of metrics, logs, and traces, but the modernization dashboard must also include business-result signals: authentication allow and deny rates, order and payment state transitions, message duplication, serialization failures, transaction rollbacks, partner errors, path or permission failures, culture-sensitive parsing errors, and reconciliation gaps. Tag telemetry with version, ring, tenant or route, and input commit so comparisons remain attributable.
Use paired queries and synthetic flows during cutover. Compare a small set of approved requests against both versions where side effects can be suppressed or isolated. For state-changing flows, compare downstream records and emitted events through a reconciliation process. A healthy CPU graph and a successful deployment do not prove that the same customer received the same result.
Failure injection should include dependency timeout, process termination during a transaction, unavailable certificate store, read-only filesystem, malformed culture-specific input, and message redelivery. In one rehearsal, remove access to the Windows certificate store from the transformed service. The expected response is not to broaden permissions. Stop the ring, confirm which certificate-loading behavior changed, restore the supported build, and decide whether the target should use a different secret-delivery design.
Recovery is the immediate operational action that restores service. It may route traffic back, restart a failed component, disable a new path, restore a configuration value, or replay a safe queue. Rollback is the controlled return to the previously supported application build and its compatible data state. Do not define rollback as manually undoing individual generated edits. The unit of rollback is an immutable, tested release plus any approved data or schema reversal procedure.
Freeze promotion and preserve logs, traces, affected identifiers, deployment events, and the exact release manifest.
Classify the failure as code, configuration, dependency, data compatibility, platform, or operational process.
Execute the rehearsed recovery action and verify business results, not only process health.
Roll back to the known supported build when stop criteria are met or diagnosis exceeds the decision window.
Reconcile writes, messages, and external effects before resuming the modernization path.
After rollback, preserve the failed generated and engineer-authored commits. Create a new remediation branch from the last reviewed point, add a regression test that reproduces the incident, and rerun all affected gates. Reversibility means the organization can return to a known state and explain what happened, not that every transformation can be cleanly reversed line by line.
14. Close the Migration With Evidence and Decommissioning
Close the modernization only when the target is the supported production system and the old path is no longer a hidden dependency. Archive the input and generated commit hashes, transformation manifest, CLI and definition versions, plan approvals, reports, classified diffs, test and performance evidence, security decisions, ring results, incidents, rollback drills, and final release record. Link each exception to an owner and expiration or permanent acceptance decision.
Decommissioning is a controlled change. Remove old deployment jobs, package feeds, servers, scheduled tasks, service accounts, secrets, certificates, firewall rules, monitoring, backups, and support procedures only after dependency observation and rollback retention periods end. Verify that no consumer still calls the legacy endpoint, no operator still relies on the old executable, and no data-recovery obligation requires the previous environment. Revoke the transformation runner's temporary credentials and clean its workspaces after evidence is retained.
The final acceptance standard is intentionally stricter than a green build: the transformed application must produce approved business results, preserve or improve security, meet performance and operational objectives, deploy reproducibly, and recover through a tested path. Every generated change must be attributable to a frozen input and reviewed by an accountable human. Unsupported or unexplained behavior remains a stop condition, not modernization debt to discover later.
Teams building those habits need foundations that transfer beyond one vendor tool. The Refonte Learning Software Engineering Program is published as a three-month program at approximately 12 to 14 hours per week, with coverage spanning full-stack development, cloud and microservices, real-time systems, performance, application security, scalable systems, and the software lifecycle. Those disciplines support the work that automation cannot own: designing contracts, testing semantics, reviewing code, operating releases, and making reversible production decisions.
