Sample Dossier · survey of 2026-09-06
Meridian Holdings: Legacy Systems Portfolio Dossier
Meridian Holdings is fictional. The three code bases are real: a small .NET data-access library written by one author between 2016 and 2025, a web application built in August 2013 that consumes that library at a 2013 version, and eShopOnWeb, the open-source .NET 8 e-commerce reference application with 641 commits by 83 authors and a live test suite.
What follows is an excerpt, lightly condensed. The full engineering Dossier runs twenty pages; a shorter executive brief for the CTO and lead architects is produced from the same artifacts. Both are downloadable below. Every technical figure traces to a named survey artifact. Business context the survey cannot see is marked as an assumption. Effort figures are planning bands, not quotes.
How to read the labels
- Automated Tool-measured. Traceable to a named artifact.
- Partial Tool-measured, then judged by an engineer.
- Manual Human work the survey informs but does not perform.
- Inferred Lifted from code with file and line. States what, not why.
1. Executive summary
What Meridian owns. Three .NET systems. Two are from one lineage: Needletail, a data-access library (3 modules, 29 files, one author), and CloudWars, a web application (36 modules, 166 files) built in 2013 that consumes Needletail at a 2013 version. The third, eShopOnWeb, is unrelated: a .NET 8 application (14 modules, 318 files) with a live test suite. The survey found no dependency between eShopOnWeb and the other two.
The recommended first move is a Confirm and Characterize phase on all three systems, run alongside a deadline-driven runtime move for eShopOnWeb: interview the five authors who hold the history, resolve 118 package references against a live advisory feed, decide the library's version policy, clear the patterns that block pinning, pin the ten areas that need it, and retarget eShopOnWeb before its runtime leaves support.
What it buys. A behavioral baseline on all three systems, a known security posture, the authors' reasoning on record, and uninterrupted vendor support for the one system that still has it. Declining leaves the legacy pair changeable only by unverified edits and puts eShopOnWeb out of support within the quarter.
- 58%of the survey is tool-driven by section weight: 4 sections automated, 7 partial, 2 manual
- 168business rules lifted from code with file and line; one enforced two ways
- 63migration-risk coding patterns to clear before behavior can be pinned
- 11–20engineer-weeks, planning band for the first phase. No functional change.
2. The portfolio at a glance
Automated inventory, dependency, and history figures; Partial rules, testability, and opportunities. With human interpretation.
| Needletail | CloudWars | eShopOnWeb | |
|---|---|---|---|
| What it is | Data-access library, 3 modules, 29 files | Web application, 36 modules, 166 files, 7 projects, 28 vendored package folders | .NET 8 e-commerce application, 14 modules, 318 files, 10 projects |
| History | 17 commits, 1 author, 2016 to 2025 | 24 commits, 3 authors, August 2013 to April 2015 | 641 commits, 83 authors, 2017 to 2025; 17 commits since 2024 |
| Public surface | 24 types, 124 methods, 2 areas | 56 types, 121 methods, 7 areas | 250 types, 244 methods, 7 areas |
| Runtime targets | .NET Standard 2.0 (active); test app on .NET 9 (end of life 2026-05-12) | 5 × .NET Framework 4.5 (maintenance-only); 2 × 4.0 (end of life since 2016-01-12) | .NET 8 for all 10 projects; support ends 2026-11-10 |
| Packages | 2, both behind current | 41 in pre-SDK manifests; advisories not checked | 77 references, centrally versioned; advisories not checked |
| Test files / areas reached | 0 / 0 of 2 | 0 / 0 of 7 | 45 / 5 of 6 |
| Business rules lifted | 43 | 20 | 105 (1 enforced two ways) |
| Migration-risk patterns | 12, all in one file | 14, ten of them static state in one repository class | 37, sixteen in the one untested area |
| Clusters / proposed waves | 2 / 2 | 31 / 5 | 5 / 6 |
| Opportunities | 4 (1 mechanical) | 15 (2 mechanical) | 6 (1 mechanical) |
| Relationships | The library CloudWars consumes | Uses Needletail at a 2013 version, with its own repository layer on top | No dependency on the other two found |
Interpretation. The legacy pair is one problem with two faces. Needletail is small, structurally simple and still active, but one author, one 1,691-line file holding all 41 of its guards and all 12 of its migration-risk patterns, and no tests make it a single point of failure. CloudWars has not changed in eleven years, sits on runtimes that stopped receiving fixes in 2016, keeps game state in static fields, and consumes Needletail at a version thirteen years behind the library.
eShopOnWeb is a different kind of asset. It is layered, tested and centrally configured; the survey found only six opportunities and none is a platform rewrite. Its risks are a calendar (one runtime target with nine weeks of support left), a concentration of untested and hard-to-test code in one area (the administration client), and a history in which 83 authors mostly touched configuration while one wrote the commercial path.
3. Findings that change decisions
Each finding states what the data says, what it means, and what it costs to leave alone.
Unsupported and expiring runtimes
Automated dependency lifecycle
Two CloudWars projects target .NET Framework 4.0, end of life since 2016-01-12. Needletail's test application targets .NET 9, end of life since 2026-05-12. Five CloudWars projects target .NET Framework 4.5, maintenance-only. eShopOnWeb's central build file sets .NET 8 for all ten projects, a long-term-support release with support ending 2026-11-10.
What it means. Three projects cannot receive vendor security fixes today, and the whole of eShopOnWeb joins them in nine weeks. The eShopOnWeb move is one central edit across ten projects, so the constraint is time, not scope.
What it costs to leave alone. Any vulnerability disclosed against those runtimes, or against CloudWars' 2013-era web stack, has no vendor remediation path except in-house patching.
The verification gap
Automated test census · Partial pinnability judgment
Needletail (22 files scanned) and CloudWars (73) have zero test files; all nine areas are test deserts. eShopOnWeb (245 files scanned) has 45 test files reaching five of its six areas; the administration client is reached by none.
What it means. In the legacy pair, no change can be verified before release except by undocumented manual testing, which blocks the runtime fixes above. The I/O evidence says pinning is feasible: eight of nine legacy areas and all six eShopOnWeb areas are rated "likely pinnable"; the CloudWars game module (61 I/O sites, 44 of them time-dependent) is rated "pin at seams".
What it costs to leave alone. Every change to the legacy pair, and every change to eShopOnWeb's admin client, is an unverified edit to production.
Knowledge concentration
Automated history · Partial interview targets
Needletail's two hottest files are 100% one author's work and change together half the time. CloudWars' web configuration is 100% one author's and its project file 83%, last touched a decade ago. eShopOnWeb has 83 authors, but 22 of its 25 concentrated files belong to one person, who holds the basket, cart and account code, the commercial path. Activity is down to 17 commits since 2024.
What it means. In each system, one person's absence removes the ability to explain why the core files are the way they are. The seeded knowledge bases carry fourteen open questions of the form "who besides this author understands this file?"
What it costs to leave alone. Every week without interviews raises the chance the answers are lost. Capturing them is days of effort in all three systems: the cheapest and most perishable item in the plan.
The dependency picture
Automated with a stated blind spot
No package advisory was checked in any system. CloudWars' 41 references sit in pre-SDK manifests that were not restored; eShopOnWeb's 77 were read statically. "0 outdated, 0 advisories" in the source data means not checked, not clean. The posture of 118 package references is unknown. Resolving them is hours to days of mechanical work and precedes every runtime move.
What it costs to leave alone. An unknown number of published vulnerabilities in two web applications with external login.
4. The calendar
These findings get worse without anyone touching the code.
| Date | What it is | Status at survey |
|---|---|---|
| 2016-01-12 | End of support for .NET Framework 4.0, target of two CloudWars projects | Passed, ten years ago |
| 2026-05-12 | End of support for .NET 9, target of Needletail's test application | Passed, four months before this survey |
| 2026-11-10 | End of support for .NET 8, the single target of all ten eShopOnWeb projects | Nine weeks from the survey date |
| OS-bound | .NET Framework 4.5, target of five CloudWars projects | Maintenance only; follows the Windows lifecycle |
| April 2015 | Last change to CloudWars | Eleven years without a commit; author availability decays with time |
5. Business rules the code enforces
Partial Every rule is Inferred: lifted from source with file and line evidence, stating what the code does and not why. Where a comment and the code disagree, the code is authoritative.
The survey lifted 168 rules across the three systems: state vocabularies, validation limits, guards, thresholds, and author notes. A few of the kind it finds:
- Catalog. An item's price must be between 0.01 and 1000 on create, and between 0.01 and 10000 on update. Both limits are live. Which applies depends on which path a request takes, and no comment records which is intended. The rule enforced two ways.
- Sessions. A cookie is valid for 60 minutes; the admin user cache refreshes every 60 seconds; the default cache is 30 seconds; seeding retries up to 10 times.
- Game engine. A worker role compares elapsed time against 30 seconds; a display name over 50 characters is handled specially. A command is one of eight states; a game action one of five.
- Data access. 41 guards in one 1,691-line file: reject a blank connection-string or table name; the isolation level cannot change until the transaction is committed; insert and update reject a null item or an undeterminable primary key.
- Author notes that describe unfinished production work. "Don't use this in production" and "change this to an environment variable" on authorization constants; "wire this up to actual email sending logic" on an email service that is a stub; a factory left unbuilt in the worker role.
The why requires interviews. Nothing above records why a price cap is 1000 or 10000, why a cookie lasts 60 minutes, or why a CloudWars turn times out at 30 seconds. Those answers, and any rule living only in someone's head, are the Manual half of this section, scheduled in Phase 0.
The rules that make CloudWars a game (turn order, damage, win conditions) are not in a form the survey can lift; they exist in method bodies and in people. The Dossier says so rather than guessing.
One hygiene finding: the web project declares code under a misspelled namespace, which the survey classifies as an external library. Any rename must account for both spellings.
6. What makes these systems hard to change
Partial This is not a style review. Only patterns with a direct line to "you cannot safely transform this yet" are reported. Formatting and naming are excluded; vendored code is skipped.
| Principle | Needletail | CloudWars | eShopOnWeb | Migration consequence |
|---|---|---|---|---|
| Avoid shared mutable state | 3 | 10 | 13 | Shared across every test in the process; characterization tests are hardest to write against exactly this |
| Dependency inversion | 3 | 1 | 4 | Cannot be exercised without the real dependency, so cannot be pinned before migration or swapped afterwards |
| Do not block on asynchronous work | 0 | 0 | 12 | A known deadlock class; an async migration moves together or not at all |
| Method length | 2 | 1 | 8 | Too long to characterize with a focused test; migrated whole and verified by eye |
| Keep interfaces narrow | 2 | 0 | 0 | Easy to transpose two arguments of the same type, which no compiler catches |
| File size | 1 | 2 | 0 | Every diff is one no reviewer can fully verify |
| Fail visibly | 1 | 0 | 0 | A migration that breaks this path produces no error and no log line |
Where the refactoring budget goes. Needletail: one file. CloudWars: the data-access layer, whose repository class keeps game state in static fields; no characterization test of it can run in isolation until that state is instance-scoped. eShopOnWeb: the administration client, at once the only untested area and the home of 16 of 37 patterns, including nine synchronous waits in one service.
Two rows need a human reading. The eight long eShopOnWeb methods are generated migration code and are regenerated rather than refactored. The two oversized CloudWars files are jQuery scripts committed inside the web project. And a pattern's absence is a statement about these checks, not a clean bill of health.
7. Recommended sequence
Partial Wave proposals and effort bands are automated; the phasing is human judgment. Bands are engineer-weeks, to be refined after Phase 0.
| Phase | Track | What happens | Exit criterion | Band |
|---|---|---|---|---|
| 0. Confirm | Both | Interview the five dominant authors; confirm every assumption; resolve all 118 package references; decide the library version policy; triage the 13 author notes; settle the price cap; capture any manual regression practice | Every open question has an owner; the version policy is written down | 2–3 |
| 1. Characterize | Legacy | Clear the blocking patterns (instance-scoped state in the repository class; seams in the game module; injected connection factories in the library), then pin all nine areas | Zero legacy test deserts; pinnability judgment per area | 5–9 |
| 1e. Characterize | eShopOnWeb | Replace the nine synchronous waits and the static state in the admin client; pin the area at its 7 network and 4 time seams | Zero test deserts; the full suite green on .NET 8 as the baseline | 2–4 |
| 2e. Runtime move | eShopOnWeb | Change the central target to the next long-term-support runtime; update the package family per the advisory report; re-run the suite | Suite unchanged on the new target; completed before 2026-11-10 | 2–4 |
| 2. Library lift | Legacy | Move the test app off .NET 9; publish a current package | Suite unchanged; a confirmed consumer builds against the new package | 1–2 |
| 3. CloudWars runtime lift | Legacy | Retire the empty placeholder project if confirmed; retarget the end-of-life projects, then the core cluster foundation first; migrate manifests; replace packages as the advisory report dictates | Suite passes on the new targets; zero open advisories | 6–12 |
| 4. Platform replacement | Legacy, conditional | Only if CloudWars has a product future: Entity Framework Core, ASP.NET Core MVC and controllers | Phase 1 suite passes on the new platform | months |
Phases 0, 1, 1e and 2e are the first funding decision: 11 to 20 engineer-weeks, of which the eShopOnWeb track must finish its runtime move by November. Needletail's 831-line method is deliberately not split before it is pinned; that is the change the survey warns "quietly changes behaviour". Phase 4 is decided, not assumed.
8. How each phase would be proven
Manual Written from the survey's stated method: pin current behavior, transform, prove parity.
| Phase | "Done" means | Evidence produced | Sign-off |
|---|---|---|---|
| 0 | Every open question has an owner and, where answerable, an answer | Three advisory reports; interview transcripts filed as expert-testimony entries; the version-policy decision; the note triage; the price-cap decision | Engineering lead |
| 1, 1e | Every area has reaching tests and a pinnability judgment; blocking pattern rows closed | Test census re-runs showing 0 deserts; coding-practices re-runs showing the shared-state, sync-over-async and dependency rows gone or accepted; suites in source control | Engineering lead, against the interview findings |
| 2e | Every eShopOnWeb project builds and every test passes on the new target | Dependency inventory re-run: active runtime, 0 open advisories; unchanged suite results; build log dated before 2026-11-10 | Security owner; engineering lead |
| 3 | All seven CloudWars projects build on supported targets with a clean, checkable manifest | Dependency inventory re-run; unchanged suite results | Security owner; engineering lead |
| 4 | CloudWars behaves identically on the new platform | Phase 1 suite passing; a parity run of any manual checklist from Phase 0 | Engineering lead and product owner |
Each phase re-runs the same survey that produced this document, so the "after" evidence is in the same format as the "before".
9. What we do not yet know
A static survey sees files, references, manifests and commit history. It does not see runtime behavior, production data flows, actual usage, deployment topology, operational practice, or anything held only in people's heads. The Dossier lists every question it raised and cannot answer, each with a method and a rough cost.
- Which systems are deployed, where, and on how many hosts? Decides whether the runtime and advisory findings are live exposure or dormant debt. Ask operations. Hours.
- Are the five dominant authors available? Every "why" in the plan comes from them. If not, Phase 0 extends and characterization proceeds at higher risk. Hours.
- Does anything else consume the library? One consumer found; "shared component" implies more. Search the repositories and package feeds. Days.
- Which price cap is intended, 1000 or 10000? The code enforces both. Interview; deployment configuration.
The same survey, on your system.
Read-only, fixed fee, success criteria declared before we start. Tell us what the system does, how old it is, what it's built on, and what's making the question urgent.