MaboaSoft Engineering Team

The Legacy Repository Discovery Checklist

A copy-paste checklist for legacy repository discovery: what to inspect, what to record, how to score confidence, and what review artifact to produce before modernization starts.

The Legacy Repository Discovery Checklist

You have inherited a legacy repository. Nobody is dead, officially. But the README is optimistic, the deployment script looks like a museum exhibit, and the backlog assumes somebody still knows how the system works.

Before you rewrite, refactor, or migrate, run discovery.

This is not another explanation of why discovery matters. That case is made in The Bus Factor Is Zero: Recovering Product Knowledge from a Legacy Repository.

This is the evidence bag.

Legacy Repository Discovery is the practice of treating a codebase as evidence and reconstructing its product model — roles, flows, integrations, constraints, risks, and unknowns — before any rewrite or migration. It is the discovery step that should precede an incremental modernization approach such as the strangler fig pattern.

TL;DR — Work top to bottom. For every finding, record: claim → evidence (repo path) → confidence (High / Medium / Low) → unknown or next evidence. Never turn a checked box into a confident claim without evidence. Finish with a single Review artifact.

Use it as an operational checklist when the repository is the best remaining source of product truth. A public, simplified Repository Discovery checklist and methodology is available on GitHub; client work uses a more detailed internal process.

How to use this checklist

Work top to bottom. Do not turn a checked box into a confident claim unless the evidence supports it.

For each finding, record what you think you found, what proves it, how confident you are, and what would resolve the remaining uncertainty.

Finding: [One product claim or observation]
Evidence: [Repository path plus what that path proves]
Confidence: [High, Medium, or Low]
Unknown or next evidence: [What still needs checking, or "None found"]

Use the confidence labels consistently:

ConfidenceUse when
HighMultiple direct evidence sources agree.
MediumEvidence supports the claim, but important details remain incomplete.
LowEvidence is weak, stale, ambiguous, contradicted, or inferred statically.

Rule: if you cannot cite evidence, do not write it as fact.

1. Inventory the evidence

Start with observations only. Inventory is the evidence log, not the product story.

Check:

  • Repository shape and major applications
  • Languages, frameworks, package files, and build files
  • Application entry points
  • README files and existing documentation
  • Tests, fixtures, seed data, schemas, and migrations
  • Configuration and environment examples
  • Assets, UI copy, translations, and localization files
  • Deployment, Docker, infrastructure, and script surfaces
  • Mobile, web, backend, worker, CLI, and service boundaries
  • Generated, vendored, compiled, or minified areas to exclude as noise

Good inventory note:

- `mobile/google-services.json` is present.

Bad inventory note:

- The mobile app uses Firebase Analytics.

The first statement records evidence. The second makes a runtime claim. That claim may be true, but it belongs later, after the runtime behavior or configuration purpose has been checked.

Record inventory findings in this format:

Inventory:

- Scanned: [Paths or repository areas inspected]
- Excluded as noise: [Generated, vendored, compiled, or irrelevant areas]
- Product conclusions deferred: [Claims that require more evidence before they become product facts]

2. Interrogate the README

Read old documentation early. Trust it late.

Check:

  • README claims compared against routes, screens, tests, and configuration
  • Setup instructions compared against current package and deployment files
  • Diagrams checked against implementation and infrastructure
  • Comments and ADRs treated as evidence, not truth
  • Contradictions recorded instead of smoothed over

Record documentation checks in this format:

Documentation check:

- Claim: [What the README, docs, comments, or ADR says]
- Supporting evidence: [Implementation, test, config, UI, or runtime evidence that agrees]
- Contradicting evidence: [Evidence that disagrees, or "None found"]
- Confidence: [High, Medium, or Low]

Treat old documentation like a witness statement. Useful, sometimes honest, and still in need of cross-examination.

3. Recover roles

Roles are not personas. They are actors with permissions, responsibilities, or system behavior.

Check:

  • Auth and authorization logic
  • Permission checks and route guards
  • Admin panels and navigation menus
  • Seed users, fixtures, and test accounts
  • Onboarding copy, report filters, audit logs, and translations
  • External systems that act like product actors

Rule: roles are permissions and responsibilities, not imaginary LinkedIn profiles.

Record each role in this format:

Role: [Actor name, such as Administrator, Customer, Operator, External System]
Evidence: [Where the role appears and what that evidence proves]
Capabilities: [What this role appears able to do]
Confidence: [High, Medium, or Low]
Unknowns: [Permission or responsibility boundaries that remain unclear]

Example:

RoleEvidenceCapabilitiesConfidenceUnknowns
AdministratorAdmin routes, permission checks, and seed user records reference admin-style access.Manage settings, review records, export data.MediumExact permission boundaries need runtime or stakeholder validation.

4. Translate the local dialect

Build a glossary only for product terms that help a reader understand behavior.

Check:

  • Domain objects that appear in UI, data, reports, or workflows
  • Workflow states and lifecycle names
  • Operational, regulatory, billing, or support vocabulary
  • Product-specific labels and aliases
  • Terms used differently across modules or eras

Record each glossary term in this format:

Term: [Business or product term]
Aliases: [Alternate names found in the repository, or "None found"]
Definition: [Evidence-backed meaning]
Where it appears: [UI, schema, tests, docs, reports, translations, or other paths]
Confidence: [High, Medium, or Low]
Unknowns: [Ambiguity or conflicting usage]

5. Group behavior into capabilities

Capabilities are what the product lets a user or another system accomplish. They are not folder names.

Check:

  • Navigation groups and page titles
  • Route clusters and controller groups
  • Forms, reports, imports, exports, notifications, and scheduled jobs
  • Test suite names and scenario names
  • Background jobs that complete user-visible work
  • Product concepts that span multiple implementation modules

Record each capability in this format:

Capability: [What the product enables someone to do]
Business purpose: [Why this capability matters to users or operations]
Roles: [Roles involved]
Evidence: [Screens, routes, tests, jobs, reports, or config that support the capability]
Confidence: [High, Medium, or Low]
Related flows: [Known flows, or "Not reconstructed yet"]

Rule: folders are not a product model. They are where the product model left fingerprints.

6. Reconstruct important flows

Flows are ordered journeys toward a business goal.

Check:

  • Routes, screens, forms, and success or error messages
  • State transitions and lifecycle fields
  • Integration tests and end-to-end tests
  • Emails, notifications, imports, exports, and scheduled jobs
  • Preconditions and decision points
  • Inferred steps marked separately from confirmed steps

Record each flow in this format:

Flow: [Flow name]
Business goal: [Outcome the user or system is trying to achieve]
Roles: [Participating roles]
Preconditions: [Required state before the flow starts, or "Unknown"]
Confirmed steps: [Steps directly supported by repository evidence]
Inferred steps: [Steps that seem likely but are not proven]
Decision points: [Branches, approvals, failures, retries, or "None found"]
Evidence: [Paths and what each proves]
Confidence: [High, Medium, or Low]
Unknowns: [Missing triggers, runtime behavior, permissions, or edge cases]

7. Do not confuse a dependency with a living integration

Integration discovery is where many legacy audits accidentally convict the wrong suspect.

Check:

  • .env examples and credential-like variable names
  • JSON, YAML, XML, properties, package, and build files
  • SDK imports, API clients, webhook handlers, and retry logic
  • Hostnames, URLs, callback paths, issuers, audiences, and DSNs
  • Docker, Compose, Kubernetes, Helm, Terraform, and deployment files
  • Mobile provider files such as Firebase or Google services configuration
  • SMTP, push notification, analytics, crash reporting, payment, storage, OAuth, and monitoring config

Classify each signal:

Signal typeMeaning
Runtime integrationCode or configuration shows active data or event exchange with an external system.
Configured boundaryProvider config, credentials, SDK metadata, or hostnames exist, but runtime usage is not proven.
Dependency-only signalA package names a provider, but no behavior is confirmed.
User-facing external linkUI opens support, legal, documentation, or help content.
Development-only referenceDocs, examples, comments, licenses, or schema URLs.
Generated noiseBuild output, vendored code, lockfile transitive metadata, or minified assets.

Runtime integrations and configured boundaries deserve explicit treatment. Development-only references and generated noise usually do not.

Rule: a package dependency is a suspect, not a conviction.

Record each integration signal in this format:

Provider or boundary: [Concrete provider, external system, device platform, or operational boundary]
Signal type: [Runtime integration, configured boundary, dependency-only signal, user-facing link, development-only reference, or generated noise]
Product behavior: [What the product appears to exchange or delegate, or "Runtime behavior not proven"]
Evidence: [Config, SDK import, API client, webhook, hostname, deployment setting, or docs]
Confidence: [High, Medium, or Low]
Unknown: [What would prove runtime use, data exchanged, ownership, or product impact]

8. Capture constraints

Constraints are rules that shape product behavior.

Check:

  • Validation rules and hard-coded limits
  • Feature flags and permission checks
  • Scheduling, retention, billing, quota, and import/export rules
  • Localization coverage and fallback behavior
  • Platform, app-store, mobile OS, deployment, and environment assumptions

Record each constraint in this format:

Constraint: [Rule, limit, platform assumption, permission, schedule, or validation]
Product impact: [How this changes user behavior, operations, or migration risk]
Affected flows: [Flows or capabilities shaped by the constraint]
Evidence: [Where the rule is enforced or configured]
Confidence: [High, Medium, or Low]

9. Record decisions, risks, and unknowns

Do not hide the uncomfortable parts in prose.

Check:

  • Observable decisions separated from invented rationale
  • Risks backed by evidence, not taste
  • Unknowns written as actionable questions
  • Credential-like findings cited by field or file path without copying secrets
  • Runtime claims downgraded when the app was not executed

Record each risk in this format:

Risk: [Evidence-backed risk statement]
Impact: [Product, operational, delivery, compliance, privacy, or migration impact]
Evidence: [Repository evidence that supports the risk]
Confidence: [High, Medium, or Low]
Next evidence: [Runtime check, stakeholder question, production log, test, or code area that would reduce uncertainty]

Record each unknown in this format:

Question: [Specific unanswered question]
Why it matters: [Decision, risk, flow, integration, or role affected by the answer]
Current evidence: [What was checked and what it did or did not prove]
Evidence that would resolve it: [Runtime observation, stakeholder answer, logs, tests, docs, or code path]
Related pages: [Roles, flows, features, integrations, constraints, or risks connected to this unknown]

Rule: unknowns are not embarrassing. False certainty is.

10. Close the case file

Do not stop when the pages look complete. Produce a final review artifact.

Use this review format:

# Repository Discovery Review

## Coverage

- Scanned:
- Excluded as noise:
- Not scanned:

## Product model

- Product frame:
- Primary roles:
- Primary capabilities:
- Primary flows:
- Major integrations and boundaries:
- Important constraints:

## Evidence quality

- High-confidence claims:
- Medium-confidence claims:
- Low-confidence claims:
- Contradictions found:

## Risks

- Evidence-backed risks:
- Risks requiring runtime validation:

## Unknowns

- Open questions:
- Evidence needed to resolve them:
- Suggested owner or next step:

## Validation

- Links checked:
- Duplicate concepts merged:
- Docs compared with implementation:
- Runtime behavior observed:
- Build/test status:

That review is not bureaucracy. It is how the next person knows whether they are reading a recovered product model or a polished guess.

Example review entry

## Unknowns

- Question: Does the mobile app use the configured Firebase project at runtime?
- Why it matters: The answer affects privacy, analytics, push notification, and release configuration review.
- Current evidence: `mobile/google-services.json` is present. No runtime Firebase initialization was confirmed in the inspected startup path.
- Evidence needed: Runtime startup logs, mobile initialization code review, or a device-level smoke test.
- Related: Mobile app, analytics boundary, push notification boundary.

Quick reference

What to recoverWhere to look
RolesAuth, permissions, admin screens, seed users
FlowsRoutes, forms, tests, emails, jobs
IntegrationsEnv vars, SDKs, configs, hostnames, deployment
ConstraintsValidation, feature flags, platform config
RisksContradictions, stale docs, untested critical paths
UnknownsMissing evidence, ambiguous naming, runtime-only behavior

The output should help people make decisions

A good Repository Discovery output lets a Product Manager understand the product without reading source code. It lets a Business Analyst see roles, capabilities, and flows. It lets an architect see boundaries, constraints, decisions, and risks. It lets a new developer orient before diving into implementation.

Most importantly, it prevents modernization from starting with false certainty.

If the checklist exposes more unknowns than answers, that is useful signal. Use the public Repository Discovery snapshot as a starting point, then bring the recovered product model into Code-to-Spec modernization when the team is ready to lock behavior with tests. Book a 20-minute call.

FAQ

What artifact should legacy repository discovery produce? At minimum, produce an inventory, a product model summary, role and capability notes, important flows, integration and constraint findings, risks, unknowns, and a final review artifact that states what was checked and what remains unresolved.

How should I score confidence during repository discovery? Use High when multiple direct evidence sources agree, Medium when the claim is supported but incomplete, and Low when evidence is weak, ambiguous, stale, contradicted, or inferred without runtime validation.

What counts as evidence in a legacy repository? Evidence can come from observed behavior, tests, source code, configuration, build files, schemas, migrations, seed data, UI copy, translations, assets, deployment files, scripts, README files, comments, and existing documentation.

How should unknowns be tracked? Write each unknown as an actionable question. Include why it matters, current evidence, what evidence would resolve it, and which roles, flows, features, integrations, constraints, or risks it affects.