
Evincia
Modernization Shield Methodology
The twelve fixed risk categories behind every Modernization Shield engagement, grouped into the four dimensions of the Modernization Readiness Score.
The Modernization Shield diagnostic measures modernization risk against a fixed set of twelve categories grouped into four dimensions. Every engagement uses the same twelve. That consistency is what makes the results comparable: between systems, between snapshots of one system over time, and between the modernization plan a client expects and the modernization plan the diagnostic actually supports.
This page is the full reference: an interactive scoring explorer just below, then twelve category deep-dives covering what each one measures, what the diagnostic engine looks for, what the senior architect evaluates by hand, and why each finding matters for a modernization. For the engagement scope, deliverables, and timeline of a Modernization Shield diagnostic, see Modernization Shield. For how this methodology fits the full assessment, from a client's code to an executive decision, see How Evincia Works.
Diagnostic framework
The 12 categories are where modernization risk hides.
The map below uses executive shorthand for the risk surface, with each label linking to the closest published category reference where the underlying evidence is described.
Platform & Runtime
Architecture & Code
Data & Integration
Operations & Decision Risk
At a glance: twelve categories, four dimensions, one score
Every engagement scores the same twelve categories, and each category rolls up to one of four dimensions. The score is the senior architect's synthesis of the engine's signals: the architect assigns the 0 to 100 Modernization Readiness Score from the dimension reads, then labels it with the Red/Yellow/Green band below. The engine does not compute it. Click any category to jump to its deep-dive below.
Platform Obsolescence
Architectural Coupling
Dependency Risk
Change Safety
See how Evincia moves from observable signals to defensible evidence.
The complete Modernization Shield methodology is visible below: all 12 categories, the engine/architect boundary, unresolved evidence, and the artifacts that reach the Legacy Modernization Risk Report (LMRR). Optional filters can emphasize inspection lanes that intersect a decision context. They do not assess, rank, or score a system.
All 12 methodology categories are shown with equal emphasis.
The interactive map is optional. The same evidence model remains available without JavaScript:
- Trace a representative finding from raw signal to resolution
- A cyber-insurance renewal or audit
- A Microsoft end-of-support date
- Private-equity technical diligence
- An AI or automation initiative
- A modernization estimate to pressure-test
- A general legacy .NET triage
- Or inspect the SocialGoal sample Modernization Risk Report / check fit for Modernization Shield.
Explore the Modernization Readiness Score
The map above shows what the methodology inspects, and where the engine's work ends and the architect's judgment begins. This explorer shows the other half: how those categories roll up into the score.
Move the sliders to see how each of the twelve risk categories affects the four dimensions and the overall Modernization Readiness Score. Click any category for what the diagnostic measures and why it matters. The widget loads with an illustrative case: twelve category scores that roll up to 52 out of 100, Yellow zone. It demonstrates how the rollup is structured, not a named engagement -- and the arithmetic is the explorer's, not the engine's: in an engagement, a senior architect assigns the dimension reads and the score. Use the reset button to return to those values.
That is the scoring structure on an illustrative case; in an engagement, the number is a senior architect's call, not an engine output. See it applied to a real public codebase in the SocialGoal sample report, or check fit for Modernization Shield to start a read on your own estate.
The four dimensions
Every assessment reads the system across four dimensions, shown on the Modernization Readiness radar; the dimension reads are senior architect judgment, not engine-computed values. Each dimension is the rollup of two to four categories.
- Platform Obsolescence. Whether the platform itself can move forward. Pairs Category 1 (Platform Obsolescence) with Category 10 (Migration Feasibility).
- Architectural Coupling. Where logic lives and how tightly it is bound to its current location. Combines Category 2 (Structural Coupling), Category 3 (Behavioral Coupling), and Category 4 (Data Complexity) with Category 11 (Embedded Business Logic Risk).
- Dependency Risk. Exposure to libraries, frameworks, and external systems the application depends on but does not control. Combines Category 6 (External Dependency Risk), Category 8 (Internal Integration Complexity), and Category 9 (External System Dependency Risk).
- Change Safety. Whether the team can confidently make changes. Combines Category 5 (Data Quality and Integrity Risk) and Category 7 (Change Failure Risk) with Category 12 (Domain Knowledge Risk).
From the four dimension reads, the senior architect assigns a single Modernization Readiness Score on a 0–100 scale -- the engine does not compute it -- displayed with a zone band: 0–49 Red (Modernization must precede AI), 50–79 Yellow (Functional, not yet AI-ready), or 80–100 Green (Structurally ready for broad AI).
What the engine produces, what the senior architect produces
The diagnostic is part automated and part hands-on. Nine of the twelve categories produce automated signals: the engine reads the source code and flags specific patterns, frameworks, packages, and structural characteristics that indicate modernization risk. Three categories are reviewed directly: the senior architect scores them using engine output, hands-on code review, and stakeholder interviews as inputs.
One of the automated nine, Data Quality and Integrity Risk (Category 5), has a hybrid character: the engine produces code-side signals, and the architect validates and extends them through direct database review. The hybrid nature is called out in that category's section because it is the only category in the methodology that works this way.
The methodology is explicit about this split because the choice is deliberate. Automating the human-extracted categories tends to produce output that sounds confident but is unreliable. The answer to "is this organization ready to execute a modernization?" is not in the source code, and treating it as if it were would undermine the diagnostic. Naming the architect's judgment as a distinct contribution lets it be evaluated as such, rather than absorbed quietly into the overall score.
If you have to defend the resulting number in front of a board, an investment committee, or an auditor, the case for it -- determinism, traceability, labeled judgment, and stated limits -- is laid out separately: why the score is defensible.
How to read this page
The twelve category sections below are organized by Modernization Readiness dimension. Each section follows the same shape: a definition, a central question, the signals or assessment areas the diagnostic produces, why it matters for modernization, and (where the source flags a boundary worth clarifying) how the category differs from another.
The cross-references between categories exist because the boundaries are easy to blur, and the methodology only works if each category is doing distinct work. Reading straight through, you will encounter the same boundary callouts from both sides. Reading by dimension, you can stop at the dimension that matches your concern.
Dimension: Platform Obsolescence
Whether the platform itself can move forward. Includes Category 1 (automated) and Category 10 (human-extracted).
Category 1 — Platform Obsolescence
Platform Obsolescence measures how old the codebase is and how far it has drifted from modern .NET. A long-running application that works fine can still score badly here: the category is not a verdict on whether the system runs today, but on whether the platform underneath it will produce blockers, breaking changes, and incompatibilities once modernization starts.
Central question
How much of this codebase is built on things that no longer exist, are no longer supported, or cannot be carried forward into modern .NET?
What the diagnostic engine detects
The engine analyzes the platform foundations of every project in the solution and produces ten signals.
- Target frameworks. The exact target framework identifier pulled from the project file of every project. Any project targeting .NET Framework 4.x or earlier is flagged as critical -- unless it also multi-targets a modern .NET version, in which case it is treated as already in migration rather than as a blocker -- and mixed framework versions across projects are flagged as a planning concern. The target framework is the single biggest determinant of migration effort. .NET Framework projects rely on platform behavior that does not exist in modern .NET, and mixed versions across projects mean the solution cannot be migrated as one unit. Sequencing has to be worked out project by project. Knowing this on day one shapes the entire plan.
- System.Web and related namespaces. Use of System.Web, System.Web.Mvc, System.Web.Http, and System.Web.Routing (the older Microsoft building blocks for web applications), flagged with project name and file location. System.Web is a hard blocker for ASP.NET Core. Its presence means a web project cannot be upgraded in place. It has to be re-architected. Finding it early prevents a team from running into a wall partway through a migration they thought was an upgrade.
- Windows-only API usage. References to registry access, the Windows event log, COM interop attributes (a long-standing way of calling older Windows components), and BinaryFormatter, each flagged with project and file location. All but the last tie the application to Windows; BinaryFormatter is flagged because modern .NET removed it outright. If the modernization target is a Linux container or a cloud platform, every occurrence is a rewrite point. Locating them scopes the cross-platform effort instead of leaving it to be discovered during the work.
- Deprecated runtime patterns. Use of AppDomain, .NET Remoting, BinaryFormatter, and SoapFormatter. These are removed or deprecated in modern .NET. Code that uses them will not compile, or will fail at runtime, after migration. Discovery converts a silent future failure into a planned, visible work item.
- ASP.NET vs ASP.NET Core determination. A binary determination per web project: classic ASP.NET or ASP.NET Core. Any project where the determination is ambiguous (referencing both frameworks at once) is flagged; a project exhibiting neither pattern is not treated as a web project and produces no determination. This establishes the migration starting line for every web project. An ambiguous result is itself a signal, usually pointing to an incomplete prior migration or an unusual hosting model that needs investigation before the project can be scored.
- Major framework detection. The name and version of major frameworks in the solution: Entity Framework (the Microsoft library applications use to read and write the database; EF6 is the older edition, EF Core the modern one), NHibernate, dependency injection containers (Unity, Castle Windsor, Autofac, StructureMap), AutoMapper, WCF (the older Microsoft technology for connecting applications to each other), Web Forms, and classic ASP.NET SignalR. Classic SignalR is flagged specifically because it requires a rewrite rather than an upgrade. Each major framework carries its own migration story; inventorying them up front lets the team estimate framework by framework rather than discovering them mid-engagement.
- NuGet package analysis. Every NuGet package reference and version per project (NuGet packages are the prebuilt, third-party code an application installs rather than writes itself), with version conflicts (the same package at different versions across projects) flagged, along with deprecated, vulnerable, and unresolvable packages. This signal is a detection feed: its package-health findings are scored and reported under External Dependency Risk (Category 6), where package risk lives. The signal itself emits only the problem findings; the full per-package inventory it reads from is reported in the solution overview, where the dependency surface becomes a known quantity before planning starts.
- Authentication and identity scheme. The authentication model the application is configured to use -- Forms, Windows, or the legacy Passport scheme -- read from the authentication mode declared in its configuration. Each scheme migrates differently: classic Forms authentication and ASP.NET Membership are re-platformed onto modern ASP.NET Core Identity, Windows authentication constrains where the application can be hosted, and the retired Passport scheme has to be re-pointed at a current identity provider. Knowing the scheme on day one tells the team which part of the security model carries forward and which has to be rebuilt.
- Authentication and identity APIs in code. Identity mechanisms used directly in code rather than declared in configuration: ASP.NET Membership and SimpleMembership, the classic forms-authentication APIs, and WS-Federation / Windows Identity Foundation (WIF). These are tied to .NET Framework and have no drop-in equivalent in modern .NET, so each use is a rewrite point in a security-model migration. Read alongside the configured scheme above, it shows how authentication is actually implemented, not just how it is declared.
- Web Forms markup and server controls. The .aspx, .ascx, and .master files themselves -- the page, control, and master directives, the <asp:> server controls and ViewState they declare, and master-page linkage -- read directly from the markup rather than inferred from the code-behind. ASP.NET Web Forms has no path to modern .NET, so the markup surface (server controls, ViewState, the page lifecycle) is a rewrite, not a port. Reading it up front sizes that rewrite instead of leaving it to surface mid-migration.
Why it matters for modernization
Platform Obsolescence is the category that determines whether the modernization is feasible at all, and whether it is one project or many. A solution where every project already targets a current .NET version with no System.Web dependencies and no Windows-only APIs is a candidate for a routine upgrade. A solution with .NET Framework 4.x projects, classic Web Forms, WCF services, and BinaryFormatter scattered throughout is a different kind of project entirely: not an upgrade but a series of rewrites and re-architectures, sequenced over months or years.
This category also changes what the others mean. High External Dependency Risk against a current .NET platform is a manageable cleanup; high External Dependency Risk against a .NET Framework 4.x platform compounds, because many of the packages that need to be replaced cannot be replaced until the platform itself moves. The same compounding effect appears across several other categories. Platform Obsolescence sets the floor everything else has to step up from.
Modernization plans that underestimate this category usually do so by treating "the application runs" as evidence that the platform is sound. It is not. The application runs because nothing has changed; modernization is the point at which things change. This category locates where the platform will fail to carry forward before that point arrives.
How this differs from External Dependency Risk
Platform Obsolescence is about the .NET platform itself: the runtime, framework features, namespaces, and Windows-only APIs the application is built on. External Dependency Risk (Category 6) is about what the application pulled in from outside that platform: the NuGet packages, libraries, and SDKs the team chose to depend on. The two often surface together, but they require different remediation: the platform changes by upgrading the runtime and removing platform-bound code, while external dependencies change by replacing packages.
In the Risk Register
For each elevated risk, the Modernization Shield diagnostic produces a Risk Register entry identifying the specific obsolescence (the framework version, the namespace, the API, the deprecated pattern) along with where it appears in the solution, what migration blocker it represents, and the path to remediation. The highest-priority findings surface in the LMRR Executive Summary's Top 5 Risks because Platform Obsolescence findings typically drive the sequencing of the entire modernization plan. They have to be addressed before most other work can begin.
Category 10 — Migration Feasibility
Architect-assessed (no automated signals).
Migration Feasibility is the senior architect's overall judgment of whether, and how, the application can realistically be modernized. It pulls the engine output together with hands-on review and stakeholder interviews into a single read on how achievable a modernization actually is. On the Modernization Readiness radar, it rolls up under Platform Obsolescence, the dimension that asks whether the platform can move forward at all.
Why this is senior architect judgment, not engine output
The engine produces no automated signals for this category. Feasibility is a holistic call that draws on every other category (structural findings, behavioral findings, data findings, platform findings) and combines them with information that exists outside the codebase: who is on the team, what they have done before, what the organization is prepared to sustain. No static analysis can answer the question "can this be modernized?" because the answer depends on people and conditions the code does not describe. The methodology treats this as a feature: the architect's judgment is the point where the engine's outputs turn into a recommendation, and the methodology names that step explicitly rather than hiding it inside a numeric score.
Assessment areas
The architect evaluates three areas to score Migration Feasibility.
- Overall architectural complexity. How tangled the system is as a whole, judged across all the structural and behavioral findings together rather than signal by signal. This tells you whether the system can be modernized incrementally (replacing one piece at a time while the rest continues to run) or whether the only safe path is to rebuild it as a single coordinated effort. It is the difference between a phased multi-quarter project and an all-or-nothing one, and the difference shapes everything else: staffing, sequencing, budget, and the kinds of failure modes the team should expect.
- Availability of modernization paths. Which of the standard modernization strategies are actually viable for this system. The four common paths are: re-platform (move the code to a new runtime with minimal changes), refactor (restructure the code in place), strangle (build the new system alongside the old one and migrate functionality across), or replace (build the new system from scratch). Each requires specific conditions in the codebase to be a credible option. A system with multiple viable paths is far lower risk than one where only a full replacement is realistic. Knowing which paths are open shapes the entire engagement recommendation and tells the client how many real choices they have.
- Organizational readiness signals. Whether the client organization has the capacity, skills, and appetite to execute a modernization. A technically feasible modernization still fails if the team that has to deliver it cannot be staffed, cannot be retained, or cannot get sustained executive support. This area is invisible to the engine and only surfaces through interviews and observation during the engagement. It often separates a project that should proceed from one that is not ready yet. That distinction is much better to discover during a diagnostic than after a modernization has stalled.
Why it matters for modernization
The other eleven categories describe the system as it is: the code, the data behind it, and the knowledge around it. Migration Feasibility tells you what to do about it. A system can score poorly across most automated categories and still be a good modernization candidate if it decomposes cleanly, if multiple strategies are open, and if the organization is ready. A system can score reasonably on automated findings and still be a poor candidate if it is structurally entangled, if every standard modernization strategy hits a blocker, or if the team that has to execute the work is overextended or unconvinced.
This is the category where the diagnostic stops being a measurement exercise and starts being a recommendation. Everything that comes before it is observation. Migration Feasibility is the architect's call. By naming it as a call rather than burying it inside a formula, the engagement can give an honest answer about whether the modernization should proceed, in what form, and on what schedule.
In the Risk Register
Migration Feasibility does not produce per-finding Risk Register entries in the same way the automated categories do. It contributes the engagement-level recommendation: the proposed modernization strategy, the sequencing it implies, the conditions under which it can succeed, and the conditions that would need to change for it to succeed. This recommendation appears in the LMRR Executive Summary as the synthesis of everything the diagnostic surfaced, and it is the part of the deliverable that leadership most often reads first.
Dimension: Architectural Coupling
Where logic lives and how tightly it is bound to its current location. Includes Category 2, Category 3, Category 4 (all automated), and Category 11 (human-extracted).
Category 2 — Structural Coupling
Structural Coupling looks at how the solution is physically assembled and asks whether that assembly will cause failures to cascade during modernization. This is not a judgment on code quality or architectural taste. A tidy-looking solution can still be dangerously coupled. The measure is purely structural: when you change one part, how much else moves with it.
Central question
Can you touch one part of this system without breaking another? Can you decompose this solution into smaller pieces, or will everything fall apart when you try?
What the diagnostic engine detects
The engine analyzes the static structure of the solution and produces seven signals.
- Project dependency fan-out. For each project, the number of other projects it directly references. Any project at or above the high fan-out threshold (default 5, configurable) is flagged. A high-fan-out project is a structural hub: changes to any of its dependencies ripple back through it, making it both a risk concentration point and a likely bottleneck when the team tries to decompose the solution.
- Circular project dependencies. Any cycle in the project dependency graph where Project A depends on Project B and Project B depends on Project A, directly or transitively, with the full dependency path reported for each cycle. Circular dependencies prevent clean decomposition. You cannot extract one project without dragging the other along with it. Finding the cycles early tells you exactly which parts of the solution cannot be pulled apart without restructuring them first.
- Layer boundary violations. Using project naming as a guide, the engine infers each project's intended layer, then flags any place where a higher-level layer references a lower-level layer it should not: a UI project referencing a data access project, a business logic project instantiating a DbContext, communication infrastructure referenced directly inside a UI or business layer. Layer violations mean the architecture's intended seams do not actually hold. A modernization plan that assumes those seams exist will break against the real structure.
- Shared or common project overload. Projects with utility-suggesting names (Common, Shared, Core, Utilities, Helpers, Base), how many other projects reference each one, and approximate size. Any shared project referenced by more than half of the other projects that also exceeds the file or line thresholds (defaults: 500 files, 50,000 lines) is flagged. Small, focused shared projects are not flagged. A bloated shared project that everything depends on cannot be changed without risk to the whole solution. It constrains the modernization sequence regardless of where the team wants to start.
- Absence of structural abstraction layers. Whether three structural patterns are present: a dedicated service layer, interface definitions for data access (IRepository or equivalent), and a dependency injection container registration. Presence or absence only, with no quality scoring. Absence of all three means the solution has no natural boundaries for decomposition. There is nowhere clean to cut. This signal is interpreted by the architect alongside the rest of the engagement, because the same absence is low risk in a small simple system and high risk in a large one.
- God classes and god methods. Any class exceeding the line threshold (default 1,000 lines) and any method exceeding its threshold (default 200 lines), reported with file, project, name, and line count. Large classes and methods concentrate too much behavior in one place. Any modernization change that touches them carries a high blast radius and high regression risk. The signal identifies the specific units that cannot be safely refactored or extracted without extensive testing.
- Project and namespace organization. Total project count, single-project solutions (where all production code necessarily lives in one place), and data access namespaces (Data, Repository, Persistence, and similar) inside a web or UI project. A single-project solution, or one where all concerns are mixed into one project, has no structural seams at all. Decomposition during modernization becomes extremely high risk.
Why it matters for modernization
Modernization is largely the work of cutting a system into smaller, independently modifiable pieces and replacing them one at a time. The strangler fig pattern, phased migrations, and most other low-risk modernization strategies all assume that the system can be decomposed along clean seams. Structural Coupling measures whether those seams actually exist.
A solution with high fan-out, circular dependencies, layer violations, and god classes does not decompose cleanly under any strategy. Each attempted cut pulls more code than expected, regression surface is wider than anticipated, and the team spends modernization budget on unplanned refactoring before the modernization work can even begin. The risk is not that the modernization fails. It is that the modernization expands. Plans that did not budget for preparatory restructuring absorb that restructuring inside the modernization timeline, with the same team and the same calendar.
How this differs from Behavioral Coupling
Structural Coupling is about the physical organization of the code: which projects reference which, where layer boundaries sit, how big the largest classes are. Behavioral Coupling (Category 3) is about the runtime behavior the code creates: static shared state, synchronous I/O, in-memory caching, thread assumptions. The two often appear together but can also diverge: a structurally clean solution can still have high behavioral coupling (and vice versa), and the remediation strategies are different. Structural problems are addressed by reorganizing projects and extracting classes; behavioral problems are addressed by changing how the code executes at runtime.
In the Risk Register
For each elevated risk, the Modernization Shield diagnostic produces a Risk Register entry identifying the specific structural element (project, class, method, dependency cycle), its measurable characteristic (fan-out count, line count, cycle path), and what its presence means for the modernization plan. The highest-priority findings surface in the LMRR Executive Summary's Top 5 Risks because structural decomposition is typically the first phase of work in any modernization, and the team needs to know what the structure will and will not allow them to do before the plan can be finalized.
Category 3 — Behavioral Coupling
Behavioral Coupling is about what the code does when it runs, not how it is laid out on disk. Where Structural Coupling looks at projects and references, this category looks at runtime: the hidden assumptions a codebase makes about shared state, threading, I/O, and caching, and whether those assumptions still hold once the application is modernized.
Central question
What will break at runtime when you change something, even if the structure looks clean? What behavioral dependencies exist between components that are invisible in the project structure?
What the diagnostic engine detects
The engine analyzes runtime patterns across the code and configuration and produces five signals.
- Static shared state. Mutable static fields -- static fields that are neither const nor readonly -- including the writable static instance fields behind singleton patterns and static state-container classes. Static utility classes and constants are not flagged. The signal is mutable shared state, not static methods or immutable values. Mutable static state creates implicit shared state between components. It fails when the application runs as multiple instances or in a distributed environment. Finding it identifies exactly what will break under horizontal scaling before scaling is attempted.
- Synchronous I/O. Synchronous file system and HTTP calls, and sync-over-async blocking patterns such as .Wait() and .GetAwaiter().GetResult(), flagged by file and pattern across the analyzed source. Synchronous database calls are not detected by this signal; data access surfaces under Data Complexity. Synchronous I/O creates hidden execution-order dependencies. Refactoring to async changes behavioral contracts and can break callers that depend on synchronous execution. The risk is highest when these calls sit deep in call chains, where async refactoring forces changes across many layers. Knowing where they are scopes that effort.
- In-memory caching and state assumptions. Use of in-memory caching mechanisms such as MemoryCache, and application-level state stores such as HttpContext.Application or HttpSessionState. These patterns assume a single process on a single server. They fail silently or produce inconsistent behavior when the application scales horizontally or moves to the cloud. Discovery surfaces the assumptions that a cloud move would violate.
- Thread and concurrency assumptions. Patterns that assume specific threading behavior: Thread.Sleep in application logic, manual thread management (new Thread, ThreadPool.QueueUserWorkItem), lock statements on shared state, volatile fields, and thread-local storage. These create behavioral dependencies on a specific threading model that may not hold after async refactoring or in a cloud environment. Finding them identifies where runtime behavior is bound to assumptions that modernization is going to change.
- Session-state mode and process affinity. How the application is configured to hold session state: in process (InProc), or in an out-of-process store such as a state server or SQL Server. InProc session pins each user to one server process. It works on a single machine and breaks the moment the application runs behind a load balancer or scales out across cloud instances, because the next request can land on a server that holds none of the session. Detecting the mode tells the team whether horizontal scaling and cloud hosting are available as-is or require moving session state to a shared store first.
Why it matters for modernization
Behavioral coupling is the category most likely to produce failures that the team does not see coming, because the dependencies it identifies are invisible in the project structure. The code compiles, the structure looks reasonable, the tests pass on a developer's machine. Then it is deployed to two servers behind a load balancer and starts behaving inconsistently. Moved to a container, the application hits a once-reliable cache that now returns wrong answers half the time. Convert a synchronous call to async, and a caller that quietly depended on its blocking behavior begins producing incorrect results.
Each of these failures has the same root cause: a runtime assumption that was true under the old hosting model and is no longer true under the new one. The patterns themselves are well understood. What is not well understood, before a diagnostic, is how many of them exist in the codebase and how deep they sit. Discovering them up front turns "the application started misbehaving after we moved it" into "we knew these patterns existed and planned the rewrites."
How this differs from Structural Coupling
Structural Coupling (Category 2) is about the physical organization of the code: projects, layers, classes. Behavioral Coupling is about how the code executes at runtime. A structurally clean solution can still have high behavioral coupling, and the two require different remediation strategies. Structural problems are addressed by reorganizing projects and extracting classes; behavioral problems are addressed by changing patterns within the code itself: converting static state to scoped state, synchronous calls to async, in-memory caches to distributed caches, manual threading to task-based concurrency. The two categories often appear together but should be planned and remediated separately.
In the Risk Register
For each elevated risk, the Modernization Shield diagnostic produces a Risk Register entry identifying the pattern, its location in the codebase, what runtime assumption it embeds, and what that assumption means for the target environment. The highest-priority findings surface in the LMRR Executive Summary's Top 5 Risks because behavioral coupling drives the post-cutover failures that are hardest to diagnose: the kind where the application appears to work and produces wrong answers, rather than the kind where it visibly fails.
Category 4 — Data Complexity
Data Complexity measures how tightly the application is wound into its data, and how much of that coupling is hidden, implicit, or scattered. A well-designed database is no guarantee of a low score; a clean schema can still be reached through dispersed, undisciplined data access. What raises risk is coupling the modernization team cannot easily find, inventory, or safely change.
Central question
How tightly is the application coupled to its data layer, and how much of that coupling is hidden or scattered in ways that will be difficult to find and safely change?
What the diagnostic engine detects
The engine analyzes data access patterns across the solution -- in code and in configuration -- and produces seven signals.
- Direct SQL in non-data layers. Inline SQL strings -- including the literal fragments of string-concatenated queries -- found outside dedicated data access projects, reported with location. SQL scattered across the application creates hidden dependencies on the database schema that are hard to inventory and dangerous to change. Locating every occurrence makes the true data coupling surface visible before anyone touches the schema.
- Stored procedure and UDF dependency. References to stored procedures (chunks of logic that live inside the database rather than the application) and user defined functions, detected by syntax pattern: CommandType.StoredProcedure usage and string values shaped like procedure or function names. Business logic embedded in the database layer is invisible to static code analysis and easy to miss during planning. UDFs called from LINQ are especially risky because EF Core has limited UDF translation support and may fail silently or throw at runtime after migration. Discovery puts database-side logic on the modernization radar where it belongs.
- ORM detection and version. The ORM framework in use and its name and version, matched against a fixed set: EF6, EF Core (with specific version), NHibernate, Dapper, ServiceStack OrmLite, Massive, PetaPoco, or RepoDb. EF6 is flagged specifically. The ORM and its version define a large part of the data layer migration story. EF6 is not forward-compatible with EF Core without significant rework. Knowing the ORM up front lets the architect scope the data access effort instead of estimating blind.
- Code-first vs database-first determination. For Entity Framework solutions, the engine reports the approach indicators it finds -- DbContext subclasses, DbSet properties, migration classes, EDMX models, auto-generated code -- and concludes code-first only when the evidence is determinate. Database-first is never auto-concluded, because a wrong database-first call drives the wrong migration strategy; everything short of a determinate code-first read is routed to the architect with the indicators attached. Code-first and database-first carry different schema traceability and migration risks, and an ambiguous indicator set is itself a signal of inconsistent data layer practices that the architect needs to dig into before scoring.
- Implicit schema dependencies. Schema-qualified references to database objects as string literals in application code outside a dedicated data access layer -- values carrying the schema, such as dbo.Customers or [Sales].[Orders]; bare, unqualified table or column names are not flagged. These are hidden schema assumptions that break silently when the schema changes during modernization. Finding them converts silent breakage into a known inventory of things that need attention.
- Shared database signals. Connection strings and data access patterns suggesting that multiple applications or services share databases: hardcoded connection strings and the database names inside them, more than one distinct database name appearing across those strings, and cross-database USE statements. A shared database creates hidden dependencies between systems. Changing the schema for one application can break another. Discovery flags a class of risk that modernization cannot safely ignore, because the blast radius extends beyond the application being modernized.
- Configuration-defined database connections. The database connections declared in the application's configuration: per project, how many connection strings exist, the data providers in use, and how many carry embedded credentials -- with credential values masked at the source and the connection string itself never recorded. This is the connection-surface inventory, independent of where the queries sit in code. It exposes provider dependencies that carry their own migration path -- a legacy or third-party ADO.NET provider, for instance -- and complements the shared-database signals read from the code.
Why it matters for modernization
Data is the part of a modernization that teams most often underestimate, and the underestimation usually shows up the same way: the code migrates cleanly, then the application starts producing wrong answers in production. The data layer is where the application's behavior is anchored, and the patterns this category detects are the ones that make that anchor implicit rather than explicit.
SQL scattered through business code, schema names referenced as string literals, business logic hiding in stored procedures, and EF6 versus EF Core mismatches are individually well-understood remediation targets. Together they describe a system where the application and its database are tangled in ways that no architecture diagram captures. Pulling them apart safely requires identifying every coupling point, not just the obvious ones. This category produces that inventory.
Shared databases warrant a separate mention. They are the signal whose blast radius extends beyond the application being modernized. A schema change made for one application can silently corrupt another, and the second application may be owned by a different team, a different department, or in some cases a different company. When this signal fires, the modernization plan has to account for stakeholders the original engagement scope did not include.
How this differs from Data Quality and Integrity Risk
Data Complexity is about how the application interacts with data: where the SQL lives, which ORM is in use, how the schema is referenced. Data Quality and Integrity Risk (Category 5) is about the data itself: whether constraints are reliable, whether triggers carry behavior the application depends on, whether the data as it exists in the database will survive migration intact. The two categories often appear together but require different investigation: Category 4 is read from the code; Category 5 is read from the database. A modernization can succeed on Category 4 and still fail at cutover because of Category 5 surprises, which is why they are scored separately.
In the Risk Register
For each elevated risk, the Modernization Shield diagnostic produces a Risk Register entry identifying the data coupling point, the project or layer where it surfaces, the schema or database object it references, and what migration risk it represents. The highest-priority findings surface in the LMRR Executive Summary's Top 5 Risks because data layer remediation typically sits on the critical path of a modernization: the application cannot move forward until the data coupling is understood, and the data coupling is rarely understood without a diagnostic.
Category 11 — Embedded Business Logic Risk
Architect-assessed (no automated signals).
Embedded Business Logic Risk is the senior architect's read on how much critical business logic has ended up in places it should not be, and how hard that logic will be to extract without changing behavior. It belongs to the Architectural Coupling dimension on the Modernization Readiness radar, alongside the categories that measure where logic lives and how tightly it is bound to its current home.
Why this is senior architect judgment, not engine output
The diagnostic engine produces no automated signals for this category. Detecting whether a stored procedure contains business rules (versus pure data access), or whether an undocumented calculation in a UI handler represents an institutional rule the business depends on, requires reading code with context, talking to stakeholders, and synthesizing what the engine surfaces with what people know. The methodology treats this as a feature, not a gap: trying to automate this assessment would produce confident-sounding output that is wrong often enough to be dangerous. The architect's judgment is the right tool for this category, and the methodology is explicit about that.
Assessment areas
The architect evaluates three areas to score Embedded Business Logic Risk.
- Business logic embedded in unexpected layers. Rules and calculations found in places they do not belong: stored procedures with business logic rather than data access, UI event handlers performing core business calculations, infrastructure or utility code carrying domain decisions. Logic in unexpected places is easy to miss during modernization and easy to break. Identifying it prevents silent behavior changes after cutover, which are among the hardest failures to detect because the application still runs. It just does the wrong thing.
- Undocumented or implicit rules discovered during analysis. Business rules that exist only in code, with no documentation and no institutional record. These are the rules most likely to be lost in a rewrite. Surfacing them is often the single highest-value part of the engagement, because a rule nobody knows about cannot be deliberately preserved. The diagnostic produces a documented inventory of these rules so the modernization team can decide which to keep, which to revisit, and which were never intended to be rules in the first place.
- Complexity of extracting logic without breaking behavior. How entangled the embedded logic is with its surroundings, and how cleanly it could be lifted out. This tells you whether the logic can be extracted by refactoring or whether the extraction is itself a major risk. A rule isolated to one stored procedure can be moved by rewriting one procedure. A rule woven through a UI handler that also performs validation, formatting, and data persistence requires far more careful work, and the work itself carries the same risk profile as the original rewrite the team was trying to avoid.
Why it matters for modernization
The failures that tend to survive a modernization undetected come from this category. Code that compiles, runs, and passes every test the team thought to write can still produce wrong answers if a business rule the team did not know about has been silently dropped or subtly changed. These failures are particularly costly because they are detected late (sometimes weeks or months after cutover, by an end user noticing that a number does not match what it used to be), and by then the modernization is complete and the team has moved on.
The mitigation is to find the embedded logic before the rewrite begins. The category delivers that: an inventory of where business rules live (not just where they ought to live), with enough architect-written context that the modernization plan can decide for each one whether to preserve, relocate, or revisit it. The plan that emerges from this work is not less ambitious. It is honest about what it is preserving and what it is changing, which is what an audit, a compliance review, or a post-modernization disagreement with a stakeholder requires.
In the Risk Register
For each significant risk, the Modernization Shield diagnostic produces a Risk Register entry naming the rule, where it currently lives, why it is at risk during modernization, and the recommended approach for preserving its behavior. The most consequential findings -- usually the undocumented rules and the most tangled extractions -- are the likeliest to rank in the LMRR Executive Summary's Top 5 Risks, so leadership has visibility into the rules that the engagement surfaced but that no one in the organization had documented before.
Dimension: Dependency Risk
Exposure to libraries, frameworks, and external systems the application depends on but does not control. Includes Category 6, Category 8, and Category 9 (all automated).
Category 6 — External Dependency Risk
External Dependency Risk measures how heavily the application leans on outside libraries, frameworks, and third-party packages, and how much trouble that reliance will cause during modernization. How well-written those packages are does not enter into it. A well-built package can still be abandoned, unbuildable on modern .NET, or licensed in a way that blocks the move. The category weighs which dependencies will become blockers, force significant rework, or introduce incompatibilities.
Central question
Which external dependencies will break, block, or complicate modernization, and how deeply is the application coupled to them?
What the diagnostic engine detects
The engine analyzes every NuGet package referenced in the solution and produces four signals.
- Deprecated packages. Packages whose referenced version is marked deprecated by their owners in the NuGet repository metadata. A deprecated package is a replacement decision, not a version bump. Early discovery turns it into a planned workstream instead of a mid-migration surprise.
- Package version conflicts across projects. Cases where the same package is referenced at different versions across multiple projects, with every project referencing a conflicting version recorded. Raising the version in one project can break another, and resolving the conflict requires coordinated changes across the solution. Conflicts in widely shared packages have the highest blast radius.
- Unresolvable packages. Packages whose metadata cannot be resolved from the NuGet repository at all -- the lookup returns nothing. An unresolvable package is an unknown that behaves like a blocker: until it is identified, replaced, or deliberately vendored, the migration cannot be priced around it.
- Packages with known vulnerabilities. Every package whose referenced version carries known security vulnerabilities, of any severity. The engine cannot tell from package metadata alone whether the fix is a patch update or a breaking major-version upgrade, so each finding carries that question forward for review. The issue this signal isolates is that remediation will intersect with modernization work and needs to be sequenced explicitly.
Why it matters for modernization
External dependencies are where modernization estimates most often run long. The pattern is consistent: teams plan a migration based on the code they own, get partway through, and discover that a critical workflow depends on a package with no path forward -- abandoned by its maintainer, no build for the target runtime, or licensed under terms that block the move.
At that point you're not migrating. You're replacing. Replacing a dependency means rebuilding the functionality it provided, finding and budgeting for a commercial alternative, or accepting residual risk you thought you'd already mitigated. The timeline and budget overruns most commonly seen in legacy .NET modernization trace back to one or two findings in this category that no one knew were there at kickoff.
This category also drives a disproportionate share of the findings that surface in audits, cyber insurance applications, and PE due diligence. "How current are your third-party dependencies, and what's your patching cadence?" has moved from technical-team table-stakes to board-level conversation in the last few years. An elevated External Dependency Risk score is a common reason an otherwise-functional system stumbles on an insurance renewal or due-diligence pass.
How this differs from Platform Obsolescence
Platform Obsolescence (Category 1) is about the .NET platform itself: runtime versions, framework features, Windows-only APIs. External Dependency Risk is about what the application pulled in from outside that platform: the packages, libraries, and SDKs the team chose to depend on. The two categories often surface together (a project still on .NET Framework usually drags some long-abandoned packages with it), but they're scored separately because they require different remediation strategies. And the ownership is one-way: every NuGet package-health finding -- deprecated, vulnerable, version-conflicted, or unresolvable -- is scored and reported here in Category 6, including the ones first picked up by the platform scan in Category 1.
In the Risk Register
For each elevated risk, the Modernization Shield diagnostic produces a specific Risk Register entry naming the package, the projects that depend on it, the current state (deprecated, CVE-vulnerable, unresolvable, version-conflicted), the migration blocker it represents, and the recommended remediation path. The highest-priority findings surface in the Legacy Modernization Risk Report (LMRR) Executive Summary's Top 5 Risks, so leadership sees them without having to read the full register.
Category 8 — Internal Integration Complexity
Internal Integration Complexity covers the wiring inside the application: how its own components, services, and subsystems talk to one another. External systems and third-party dependencies are scored elsewhere. This category weighs whether that internal wiring depends on patterns, protocols, or infrastructure assumptions that will not survive a move to modern .NET or the cloud.
Central question
How are the internal pieces of this application connected to each other, and will those connections break, require significant rework, or create hidden dependencies when the application is modernized or moved to the cloud?
What the diagnostic engine detects
The engine analyzes how components within the solution communicate with one another -- in code and in configuration -- and produces six signals.
- WCF and SOAP internal service communication. References to System.ServiceModel, WCF service and operation contracts, and WCF client and binding types anywhere in the solution's source. Each finding is reported per project, naming the exact WCF constructs found; whether a given service is internal or external -- and whether the project hosts or consumes it -- is drawn in review. WCF is not supported in modern .NET. Internal services using it must be rewritten to REST, gRPC, or CoreWCF before or during modernization, and the rewrite has to be scoped on both sides of every connection.
- File-based integration patterns. Components communicating by reading and writing files to shared directories: hardcoded UNC network paths used as integration points, polling patterns that check directories for new files, FileSystemWatcher used as a trigger mechanism between components. These patterns assume a shared local or network file system that does not exist in cloud or containerized environments. They are easy to overlook in planning because they do not look like integrations in code. They look like file operations.
- Windows-specific inter-process communication. Usage of MSMQ (System.Messaging), named pipes (any use of NamedPipeServerStream or NamedPipeClientStream in source), and COM interop used for component-to-component communication. These mechanisms assume Windows infrastructure and will not work in cross-platform or cloud environments without significant rework. Discovery scopes the IPC rewrite and flags a dependency on the host operating system that constrains where the application can run.
- Deprecated internal serialization. BinaryFormatter or SoapFormatter used to serialize data passed between internal components. This is tracked separately from general deprecated runtime patterns because the integration role is what makes it a modernization blocker: component-to-component communication cannot proceed until the serialization mechanism is replaced. BinaryFormatter has been removed from modern .NET; any component pair relying on it requires a coordinated rewrite of both ends.
- Configuration-defined WCF endpoints and bindings. The WCF services and clients declared in the application's configuration, including the binding each one uses (basicHttp, netTcp, wsHttp, and the rest). Where the code signal above shows that WCF is present, this reports, per project, the endpoint counts (service vs client) and the set of bindings in use -- and the binding is what sets the migration path. Some can move to CoreWCF on modern .NET; others have no supported equivalent and force a redesign to REST or gRPC. Reading the endpoints from configuration inventories every WCF connection that has to be re-homed, on both the hosting and consuming sides.
- Project-referenced COM interop. COM and ActiveX type libraries wired in through the project file (a <COMReference>), reported per project with the type-library name, version, and registration GUID. COM is Windows-only with no cross-platform equivalent, so each referenced component is a replacement or re-hosting item before any move off Windows. This is the configuration-side companion to the Windows-specific IPC signal above -- a dependency the application can rely on without any visible COM attribute in its own source.
Why it matters for modernization
Internal integration patterns are where a modernization plan most often discovers that the "lift and shift" assumption does not hold. The application looks like one logical unit to its users, but internally it is held together by a web of WCF endpoints, shared directories, and Windows-specific message queues that have no equivalent in the target environment. Moving the application means rewiring it.
Each of these signals represents infrastructure that has to be replaced, not just transported. WCF services become REST or gRPC. File-based handoffs become message queues or APIs. MSMQ becomes a cloud-native queueing service. BinaryFormatter becomes JSON, Protobuf, or another supported serializer. Each replacement is well-understood individually. The count of internal connections, though, is often surprisingly high, and a contained-looking project sprawls once that count surfaces mid-modernization. A project quoted as a move turns into a rebuild, and the number that grows is the one finance is watching.
How this differs from External System Dependency Risk
External System Dependency Risk (Category 9) is about how the application talks to things outside its boundary: third-party APIs, vendor SaaS, partner systems. Internal Integration Complexity is about how the pieces of the application talk to each other. The same protocol (WCF, for example) can appear in both categories, but the remediation strategies differ: an internal WCF service can be rewritten freely, while an external WCF endpoint may require coordination with a third party who controls the other end.
In the Risk Register
For each elevated risk, the Modernization Shield diagnostic produces a Risk Register entry naming the integration point, the components on both sides, the protocol or mechanism in use, and what it has to become in the modernized environment. The highest-priority findings surface in the LMRR Executive Summary's Top 5 Risks because internal integration replacement is typically a phase of work that has to be planned for explicitly. It does not happen by accident during a runtime migration.
Category 9 — External System Dependency Risk
External System Dependency Risk measures what the application depends on beyond its own boundary: third-party services, vendor APIs, partner systems, outside infrastructure. The internal wiring between an application's own components is scored separately, in Internal Integration Complexity. This category covers everything the application reaches out to but does not control, and what that lack of control will cost when modernization forces those dependencies to change.
Central question
What external systems does this application depend on, how tightly is it coupled to them, and what happens during modernization when those dependencies need to change, be replaced, or be re-integrated?
What the diagnostic engine detects
The engine analyzes how the application reaches outside itself and produces four signals.
- External API and service dependencies without abstraction. Direct calls to external HTTP endpoints or REST APIs with no abstraction layer: HttpClient or WebClient usage that appears inside business logic or UI layers rather than in a dedicated integration project. When an external API changes, is versioned, or has to be replaced during modernization, the changes ripple into application logic instead of being contained to one integration point. The signal shows where the integration surface is unprotected and how widely a single external change would spread.
- Infrastructure and environment assumptions. Hardcoded assumptions about the runtime environment embedded in the code's string literals: non-local IP addresses and UNC network-share paths that tie the application to specific machines and network topology. These assumptions break when the application moves to a new environment, a cloud platform, or a containerized deployment. Discovery inventories what has to change before the application can move at all, rather than letting those assumptions surface as failures after the move.
- Third-party SDK deep coupling. Third-party SDK packages referenced across multiple projects rather than isolated to a dedicated integration project, read from the solution's package inventory: an SDK referenced by two or more projects outside the integration layer is flagged, with those projects named. Deep coupling to a third-party SDK means that replacing or upgrading it during modernization requires changes across the entire codebase rather than in one contained area. The signal shows how widely an SDK change will spread, which is often much larger than a dependency list suggests.
- Legacy protocol dependencies. References to legacy communication protocols used for external system integration: SOAP via System.Web.Services or service references, and WCF via System.ServiceModel (the engine flags any WCF usage; internal versus external is drawn in review). These protocols have limited or no support in modern .NET and cloud environments. They are often underdocumented and only fully understood once modernization is already underway. Early discovery turns them into discrete, planned workstreams instead of mid-project discoveries.
Why it matters for modernization
External dependencies are the part of a system the team does not control, and that lack of control is what makes them dangerous in a modernization. Internal code can be rewritten on the team's own schedule. External APIs get deprecated, vendors change pricing or terms, partner systems version their interfaces, and infrastructure providers retire services, all on schedules the team has to react to rather than set.
A modernization is the moment when those reactions all compound. Moving to a cloud platform means infrastructure assumptions have to be made portable. Updating frameworks means SDK versions have to follow. Replacing legacy integration protocols means coordinating with the other end of every connection. When external dependencies have been allowed to leak across layers, each of those moves becomes a multi-team coordination problem instead of a contained engineering task.
The most commonly underestimated signal in this category is third-party SDK deep coupling. Teams generally know which APIs they call. They less often know how widely a vendor SDK's types have propagated through their own code, and discover, mid-migration, that an SDK upgrade requires changes in projects they did not think touched that SDK at all.
How this differs from External Dependency Risk
External Dependency Risk (Category 6) is about libraries, frameworks, and packages the application pulled in at build time: the contents of its NuGet packages. External System Dependency Risk is about the runtime integrations the application makes with systems outside its boundary. The same vendor can appear in both categories at once, for example a SaaS provider whose SDK is a NuGet package (Category 6) and whose hosted API is called at runtime (Category 9), but the modernization implications are different and the remediation paths are different.
In the Risk Register
For each elevated risk, the Modernization Shield diagnostic produces a Risk Register entry naming the external system or integration point, where in the codebase the dependency surfaces, how widely it has spread, and what has to change for the modernized environment to talk to it correctly. The highest-priority findings surface in the LMRR Executive Summary's Top 5 Risks because external dependencies frequently require coordination with parties outside the engagement, and lead time on that coordination has to be planned at the start, not discovered mid-stream.
Dimension: Change Safety
Whether the team can confidently make changes. Includes Category 5 (automated, with a hybrid pattern), Category 7 (automated), and Category 12 (human-extracted).
Category 5 — Data Quality and Integrity Risk
Automated with a hybrid pattern. Most signals only fully resolve through direct database review. See "A note on what the engine can and cannot detect" below.
Data Quality and Integrity Risk is about the data itself, not the code that reaches it. Even when every line of data access migrates cleanly, the rows, constraints, triggers, and accumulated quirks already in the database can break the modernized application. This category measures whether the data, as it actually exists, will survive migration intact and behave consistently afterward, rather than producing silent failures or corruption that no one catches for weeks.
Central question
Even if the code migrates cleanly, will the data itself cause the modernized application to fail?
A note on what the engine can and cannot detect
Most of the risks in this category live in the database itself (in actual rows, constraints, triggers, and stored procedure side effects), not in the application code. Static code analysis can detect signs that these risks are present, but confirming and scoring them requires direct database review. The engine produces the code-side signals listed below; the senior architect then inspects the database directly to validate and extend what the code surfaced. The result is a hybrid finding: part automated, part hands-on. It is the only category in the methodology that works this way, and the deliverable surfaces both layers honestly so the client sees what came from the code and what came from the architect's review.
What the diagnostic engine detects from code
The engine analyzes patterns in application code that suggest data quality or integrity issues exist in the underlying database, and produces four signals.
- Database constraint workarounds in application code. Catch blocks whose declared exception type is a known database exception type -- SqlException, DbUpdateException, ConstraintException, and similar -- wherever they appear in application code. This pattern suggests the database constraints are missing, disabled, or unreliable, and the application is compensating for them in code. When data integrity depends on application code rather than the database, and that compensating logic is missed or behaves differently after migration, silent data corruption can result. Discovery points at exactly where data integrity actually lives.
- Trigger dependency signals. Because trigger presence cannot be confirmed or ruled out from application code, the engine always raises a single solution-wide trigger-dependency finding, noting whether the codebase performs data-write operations at all. The finding is explicitly flagged as ambiguous and routed to senior architect review and direct database inspection. Triggers are invisible to static code analysis. If the application depends on trigger behavior and that behavior is not accounted for during migration, data will be silently wrong after cutover. The value of this signal is that it flags the gap honestly and tells the architect where to look, rather than guessing.
- Defensive data handling patterns. Code that defensively cleans or normalizes the data it reads: null coalescing on values coming back from data access, and consistent string trimming or casing normalization applied to values read from the database. These patterns suggest the application cannot trust its underlying data and is compensating in code. During modernization, that compensating logic has to be identified and either preserved deliberately or addressed at the data layer. Missing it means the modernized application inherits the bad data without the patches.
- User Defined Type (UDT) usage. References to SQL Server user defined types in SqlParameter declarations with explicit type names, and stored procedure calls passing structured parameters. UDTs are not well supported by EF Core or most modern ORMs. Code that passes or receives them will likely need rewriting during migration. Discovery identifies a specific, concrete rewrite item rather than a vague risk.
Why it matters for modernization
The failures this category warns about are the ones most likely to be invisible until the modernized application is already in production. Code that runs and tests that pass do not prove the data is sound. They only prove that the application behaves correctly with the data it has seen. The data it has not seen, in production at scale, may have problems the test data never exposed.
Database constraints that were disabled to fix a deadlock years ago. Triggers that quietly populate audit columns the application never writes. Defensive code that handles bad data so old that no one remembers it exists. These accumulate in long-running production systems, and they are not visible to anyone reading the application code. The application code shows the symptoms (the try/catch blocks, the null coalescing, the cast-to-default patterns) but not the underlying cause. The cause is in the database itself.
A modernization that ignores this category typically ships, runs, and starts producing incorrect output that no one notices for weeks, because there is no compile error and no runtime exception. Finding the data-side risks before cutover prevents that kind of silent failure, and finding them well requires both the code signals the engine produces and the database review the architect performs.
How this differs from Data Complexity
Data Complexity (Category 4) is about how the application accesses data: where SQL lives, which ORM is in use, how the schema is referenced. Data Quality and Integrity Risk is about the data itself: whether the data is consistent, whether constraints are reliable, whether triggers carry behavior the application depends on. Category 4 is read from the code; Category 5 is read from the database. The two often appear together but require different investigation. A modernization can succeed on Category 4 and still fail at cutover because of Category 5 surprises, which is why they are scored separately.
In the Risk Register
For each elevated risk, the Modernization Shield diagnostic produces a Risk Register entry naming the data quality or integrity risk, where it appears (in code, in the database, or both), what migration failure mode it suggests, and the recommended approach for confirming and remediating it. The highest-priority findings surface in the LMRR Executive Summary's Top 5 Risks because data quality risks are the failures most likely to survive a modernization undetected, and leadership has to know that the risk exists before they sign off on the cutover.
Category 7 — Change Failure Risk
Change Failure Risk asks a forward-looking question: once the modernization team starts changing this system, how often will those changes break something? Whether the application works today says nothing useful about that. The answer depends on whether the system has the structural and operational characteristics that let changes be made safely, verified, and rolled back when something goes wrong.
Central question
When you start making changes to this system, what is the probability that those changes will produce failures that are hard to detect, hard to diagnose, and hard to reverse?
What the diagnostic engine detects
The engine analyzes the operational safety characteristics of the solution and produces four signals.
- Test coverage. Whether test projects exist in the solution, which testing frameworks are in use (NUnit, xUnit, MSTest), and the ratio of test projects to production projects. Solutions with no test projects are flagged as a deterministic finding. Where tests do exist, the engine reports counts and ratio only and leaves adequacy to senior architect review. Test coverage is the safety net that catches regressions introduced by modernization changes. A solution with no tests has no net; the engine reports the facts so the architect can judge how much of a net actually exists.
- Monolithic deployment structure. Whether the solution produces a single deployable artifact or multiple independently deployable units, inferred from the solution's project structure: a single web or executable project with no independent supporting service projects reads as a monolith. A monolithic deployment means any change requires redeploying everything, and a failed change affects the entire system rather than a contained part. Knowing the deployment structure tells you how contained, or uncontained, a failed modernization change will be.
- Hardcoded configuration. API endpoints, environment-specific URLs, and hardcoded IP addresses embedded as string literals in source code instead of externalized to configuration files or environment variables (localhost and loopback values are excluded; hardcoded connection strings surface through the data-layer signals rather than here). Hardcoded configuration breaks portability across environments. During modernization, moving the application to new infrastructure becomes a code change instead of a configuration change. Discovery inventories the portability blockers before the move is attempted.
- Absence of observable failure detection. Whether the application has meaningful logging, exception tracking, or error reporting: logging frameworks (Serilog, NLog, log4net, ELMAH, Microsoft.Extensions.Logging) and exception tracking integrations (Application Insights, Sentry, Raygun). Solutions with none of these are flagged. The risk is not that logging is absent for its own sake. The risk is that when a modernization change introduces a failure, there is no mechanism to detect it quickly. Silent failures become invisible, which extends the time to diagnose and recover. The signal shows whether the team will be able to see what they break.
Why it matters for modernization
A modernization is a long sequence of risky changes. Code is rewritten, frameworks are upgraded, infrastructure is replaced, integrations are reworked. Each change has the potential to introduce a failure, and the team's ability to ship that change safely depends on four things: catching the failure before it reaches users (tests), containing the failure when it does reach production (deployment isolation), moving the application between environments without touching code (externalized configuration), and seeing the failure clearly when something goes wrong (logging and monitoring).
A system that has none of these is one where every modernization change is a high-stakes bet. The team cannot validate changes in advance, cannot limit the blast radius if something breaks, and cannot diagnose what went wrong after the fact. Plans built on this foundation usually compensate with caution (slower change pace, more manual review, longer freeze windows), which extends the modernization timeline without actually reducing the risk it carries.
A system that has all four is one where modernization changes can be made at speed and with confidence. The signals in this category determine which kind of system the team is starting from, and therefore how aggressive the modernization plan can responsibly be.
How this differs from Structural Coupling
Structural Coupling (Category 2) is about whether the code is organized to cause cascading failures when changes are made. Change Failure Risk is about whether the system has the operational safety characteristics (tests, deployment isolation, configuration management, observability) to be changed at all. The two are independent: a structurally clean solution can still have high Change Failure Risk if it has no tests and no observability, and a structurally tangled solution can have low Change Failure Risk if it has been carefully wrapped in tests and monitoring over the years. The two categories together describe whether modernization changes can be made safely. Neither one alone is enough.
In the Risk Register
For each elevated risk, the Modernization Shield diagnostic produces a Risk Register entry identifying the missing safety characteristic, where in the solution it is absent, what kind of modernization change is most at risk because of the absence, and the recommended approach for building the missing capability. The highest-priority findings surface in the LMRR Executive Summary's Top 5 Risks because operational safety is a precondition for keeping modernization moving. Without it, the modernization is either slow or unsafe, and neither outcome is acceptable.
Category 12 — Domain Knowledge Risk
Architect-assessed (no automated signals).
Domain Knowledge Risk is the senior architect's call on whether the knowledge needed to modernize the system safely actually exists and can be reached. On the Modernization Readiness radar it falls under Change Safety, grouped with the categories that bear on whether a team can change the system with confidence.
Why this is senior architect judgment, not engine output
The engine produces no automated signals for this category. Knowledge (whether a system is documented, whether the documentation is current, whether critical understanding sits with one person or many) cannot be detected from source code. It surfaces only through interviews, documentation review, and observation during the engagement. The methodology treats this as a feature: the question of whether a team has what it needs to modernize safely is too important to be answered by code analysis alone.
Assessment areas
The architect evaluates three areas to score Domain Knowledge Risk.
- Availability of documentation. Whether the system, its rules, and its integrations are documented at all, and how current and trustworthy that documentation is. Absence of documentation means the modernization team is working blind, reconstructing intent from code. That reconstruction is slow, error-prone, and a major source of project risk. Out-of-date documentation can be worse than no documentation, because it gives the team confidence in answers that are no longer true.
- Key person dependency signals. Whether critical knowledge sits with one or a few individuals rather than being spread across the team or written down. A single-person dependency is a major project risk. If that person becomes unavailable (leaves the company, takes a long medical leave, is reassigned), the modernization can stall outright or proceed on guesses. Identifying the dependency early lets the client mitigate it before it becomes a problem the engagement has to absorb.
- Complexity of the domain relative to available knowledge. Whether the difficulty of the business domain outstrips what the available people and documents can actually explain. A complex domain with thin knowledge coverage is where modernization projects most often produce incorrect behavior. This is the assessment that tells you whether the knowledge base is strong enough to support the complexity it has to cover, or whether the modernization will be running ahead of what anyone in the room actually understands.
Why it matters for modernization
A modernization is a translation. The behavior of the existing system has to be preserved or deliberately changed, and that preservation requires someone to know what the existing system does, not just at the level of "it processes orders" but at the level of "it processes orders with a specific rounding rule that an auditor required years ago." When the people and documents that could supply that level of detail are missing or thin, the translation happens anyway. It just happens on guesses.
The failures from this category are particularly costly because they tend to appear after the modernization has shipped and the team has moved on. A user notices that a number is different from what it used to be. A compliance review surfaces that a rule the auditor required is no longer being enforced. A customer raises an issue about a behavior the team did not realize existed. Each of these failures takes time to trace, time to fix, and time to re-validate, and the rework happens after the modernization budget has been closed.
Surfacing the knowledge gaps before the modernization begins lets the engagement either fill them (through additional documentation, additional stakeholder interviews, or scope adjustment) or plan around them honestly. The plan that acknowledges what is not known is far more reliable than the plan that assumes everything important is in the code.
In the Risk Register
For each significant risk, the Modernization Shield diagnostic produces a Risk Register entry naming the knowledge gap, what part of the system it affects, what kind of modernization failure it would most likely produce, and the recommended approach for closing or mitigating the gap: typically a combination of additional interviews, supplemental documentation work, or scope adjustment. The highest-priority findings surface in the LMRR Executive Summary's Top 5 Risks because knowledge gaps are usually invisible to leadership before the modernization begins, and naming them explicitly is often the difference between a project that proceeds informed and one that proceeds optimistically.
Find these out on a fixed-scope assessment, or find them out mid-project.
Modernization Shield applies this approach to a specific .NET and SQL Server estate and turns the evidence into an executive summary, risk register, "What Will Break First?" analysis, supporting readiness score, and recommended modernization sequence.
Review the evidence-based approach or book a methodology walkthrough →
