doc-and-modernize — скилл для GitHub Copilot: что делает и как ставить
Анализирует локальный репозиторий, собирает архитектурный документ со ссылками на файлы и формирует пошаговый план миграции устаревшего стека.
npx skills add github/awesome-copilot --skill doc-and-modernizeЧто делает doc-and-modernize
Скилл работает локально прямо по кодовой базе на диске. В режиме документации он считывает коммит через Git, проверяет манифесты вроде package.json или Cargo.toml, изучает конфиги CI и строит один markdown-файл с картой системы. Все утверждения подкрепляются номерами строк, а токены из ссылок на репозиторий автоматически вырезаются.
Режим модернизации использует полученный документ, чтобы составить план рефакторинга или перехода на новый стек. Скилл не ждет идеального прохождения тестов на старом коде: он предлагает проверку через короткий spike и поэтапное движение по уровням безопасности.
Ставьте этот скилл, если нужно разобраться в незнакомом монолите или переписать старый сервис. Если проект крошечный и состоит из пары скриптов, глубокий аудит избыточен.
Какие задачи решает
- составить архитектурный документ для онбординга новых инженеров
- зафиксировать стек, команды сборки и рантайм проекта по файлам на диске
- спланировать миграцию или переписывание устаревшей системы
- провести экспресс-проверку жизнеспособности старого стека
Примеры запросов агенту
- Подготовь архитектурный документ по этой кодовой базе
- Составь пошаговый план миграции с этого легаси-стека
- Проведи глубокий аудит системы и зафиксируй команды сборки
Как установить doc-and-modernize
1Через Skills CLI (Vercel)
npx skills add github/awesome-copilot --skill doc-and-modernize2GitHub CLI
gh skill install github/awesome-copilot doc-and-modernize3Вручную: положить файлы
.github/skills/doc-and-modernize/SKILL.md1Через Skills CLI (Vercel)
npx skills add github/awesome-copilot --skill doc-and-modernize -a claude-code2Вручную: положить файлы
~/.claude/skills/doc-and-modernize/SKILL.mdПапка скилла целиком; для одного проекта — .claude/skills/doc-and-modernize/
Вручную: положить файлы
.agents/skills/doc-and-modernize/SKILL.mdДля всех проектов — ~/.agents/skills/
Вручную: положить файлы
.cursor/skills/doc-and-modernize/SKILL.mdCursor читает и .agents/skills/, и .claude/skills/
Командой платформы
gemini skills install https://github.com/github/awesome-copilot --path skills/doc-and-modernizeВручную: положить файлы
.devin/skills/doc-and-modernize/SKILL.mdСтарый путь .windsurf/skills/ тоже читается
Claude.ai
Упакуйте папку в zip и загрузите в Settings → Capabilities → Skills
Из того же набора554
Весь набор →Похожие
Вопросы о doc-and-modernize
Как установить doc-and-modernize в GitHub Copilot?
Выполните команду npx skills add github/awesome-copilot --skill doc-and-modernize или используйте CLI: gh skill install github/awesome-copilot doc-and-modernize.
Что делает скилл doc-and-modernize?
Он сканирует локальный код на диске, собирает архитектурный отчёт со ссылками на строки файлов и формирует план модернизации устаревших систем.
Почему скилл читает файлы локально, а не через API GitHub?
Локальный анализ не упирается в лимиты API и описывает точное состояние репозитория на диске. Внешние сетевые запросы используются только как крайняя мера, если нужных данных нет в кодовой базе.
Исходный текст
SKILL.md · MIT
---
name: doc-and-modernize
description: >-
Two related workflows for a locally-cloned codebase, in one skill.
Documentation mode produces a single, comprehensive, verifiable architecture
document primarily by reading files on disk (local-first) — use it whenever the user wants to
understand, map, document, research, or onboard onto a codebase ("research
this repo", "write up the architecture", "do an architecture deep dive",
"document how this codebase works", "map the system design", "create an
onboarding doc"). Modernization mode generates a
phased plan to modernize, migrate, upgrade, or rewrite a legacy system
("modernize this", "plan the migration", "how would we rewrite this", "how do
we get off this legacy stack"); if no architecture document exists yet it
first runs Documentation mode, then continues straight through to the plan. It
assumes the legacy stack may be dead, runs a time-boxed feasibility spike, and
picks the highest achievable rung on a safety ladder instead of demanding a
fully-green legacy CI gate up front.
---
# Documentation & Modernization
Two complementary workflows for a repository the user already has checked out
locally, bundled as one skill:
- **Documentation mode** — produce one definitive, cited architecture document
from the code on disk. Ideal for onboarding, system-design maps, or as the
evidence base for a modernization effort.
- **Modernization mode** — turn that architecture into a phased, safety-laddered
plan to upgrade, migrate, or rewrite a legacy system.
## Mode selection
- If the user wants to **understand, document, map, research, or onboard onto** a
codebase, run **Documentation mode**.
- If the user wants to **modernize, migrate, upgrade, or rewrite** a system, run
**Modernization mode**. Modernization mode is self-sufficient: if no
architecture document exists yet, it runs the **Documentation mode** workflow
first (in the same pass), then continues straight through to the plan.
When in doubt, produce the architecture document first — it is the audited
evidence base both modes rely on.
## Documentation mode
Generate one definitive, cited architecture document for a repository the user
already has checked out locally. The goal is a writeup someone could hand to a
new engineer as their onboarding reference — broad enough to cover the whole
system, deep enough on the hard parts to be useful, and trustworthy because
every claim traces back to a file on disk.
### Why local-first
Reading from the local checkout (not the GitHub API or the web) is the deliberate
**default**. It is faster, free, avoids rate limits, and — most importantly — it
describes *the exact code in front of you* rather than whatever `main` happens
to look like remotely. The one tradeoff is that remote-only facts (star counts,
full CI run history, sibling repos) aren't visible. That's fine: state those as
out-of-scope or mark them `[UNVERIFIED]` rather than guessing.
Local-first is not local-*never*-remote: a web/API lookup is a deliberate
**last-resort fallback**, reserved for a fact that genuinely cannot be determined
from disk and that materially matters to the document. When you do reach for it,
flag the result clearly (e.g. `[UNVERIFIED]` / sourced-remotely) so the reader
knows it didn't come from the checkout, and never let it become the easy path
that displaces reading the code on disk.
### Workflow
1. **Establish identity first.** Run `git remote -v`, `git branch --show-current`,
and `git log -1` so the document is anchored to a specific remote, branch, and
commit. A reader must be able to tell which snapshot this describes. Remote
URLs can contain embedded credentials (e.g. `https://<token>@github.com/...`)
— **redact any credentials/tokens** from the URL before recording it in the
document.
2. **Detect, don't assume.** Read the real manifests (`go.mod`, `package.json`,
`Cargo.toml`, `pyproject.toml`, `pom.xml`, etc.), the `Makefile`/task runner,
CI config, and any repo-specific agent or contributor docs (`AGENTS.md`,
`CONTRIBUTING`, `README`, `docs/`). These are the source of truth for the tech
stack and commands — prefer them over your prior knowledge of the framework.
3. **Map breadth, then drill into depth.** First build the whole-repo map (the
three lenses below), then pick the 2-3 hardest subsystems and go deep on them.
4. **Verify as you go.** Open the files you cite. If you reference a line number,
you should have actually read that line. Unsupported claims are worse than
omissions here — the whole value of this document is that it can be trusted.
### Output structure
Produce a **single Markdown file** with the sections below, in this order. Adapt
the headings to the actual project (a CLI tool has no "frontend" lens — fold that
slot into whatever matters for that repo), but keep the three-lens shape and the
verification discipline.
#### Part 1 — Whole-repo technical deep-dive
- What the repository is (one paragraph, cited to README).
- Tech-stack detection table: layer | technology | evidence (file+line).
- Entry points (backend, frontend, CLI — whatever applies).
- **Commands & Verification Inventory** — a table of the canonical project
commands (`command | purpose | evidence`), verified against the task runner /
manifests / CI config, not guessed. Cover build, run/serve, test (and how to
run a single test), lint, format, and — where they exist — typecheck,
end-to-end/smoke, contract, and any other gate commands, plus the CI
workflow(s) that run them and on what trigger. **Also record whether CI is
*enforced*** — i.e. whether any workflow is a **required status check /
branch-protection rule** that actually blocks merges, versus one that merely
runs — since that distinction is a manual, human-configured setting that
Modernization mode must surface, not assume. Enforcement usually cannot be
determined from the local checkout alone: ask the user, or mark it
`[UNVERIFIED]` unless confirmed from an authoritative source (any remote
lookup is a flagged last resort, per the local-first rule above). This
inventory is the source of
truth that downstream planning (Modernization mode) cites so its exit
criteria are runnable, not aspirational. Detect these per-ecosystem (npm/yarn/
pnpm, `make`, `just`, `cargo`, `go`, `poetry`/`tox`/`nox`, `gradle`/`maven`,
etc.) — do not assume a stack. Mark any command you could not verify
`[UNVERIFIED]`.
- Directory layout for each major area, with a one-line purpose per directory.
- **Deployment & Runtime Surface** — a table of every place the language/runtime
and backing-service versions are pinned *for running* the system (not just
building it): container base images (`Dockerfile`/`Containerfile`,
`docker-compose*` build contexts), CI runner images / `setup-*` versions,
`engines`/`.nvmrc`/`.tool-versions`/`runtime.txt`, serverless/lambda runtimes,
and stateful data-store image tags (DB/cache/broker/search). Cite each with
file+line. This surface is what a later platform/runtime bump must move in
lockstep — flag any drift between build-runtime and run-runtime here so it's
visible before a modernization plan is written.
- **EOL / dead-dependency scan** — call out frameworks, runtimes, base images,
and libraries that are end-of-life, unmaintained, or removed in a likely target
major (e.g. a framework whose next major renames namespaces or drops a
component family). Mark each `[INFERRED]`/`[UNVERIFIED]` as appropriate. This is
the raw material Modernization mode's feasibility spike and hazard red-team
build on.
- Data/storage layers, APIs, plugins/extensions, background jobs, CI/CD, testing.
#### Part 2 — Context & ecosystem
- Local checkout identity table (remote, branch, HEAD commit, version, license).
- Repo-specific agent/contributor docs present, and what rules they encode.
- Developer gotchas (test watch-mode defaults, slow builds, codegen-must-commit,
pre-commit hooks) — each cited.
- How this project relates to its broader ecosystem or sibling services, *as
visible from disk* (build tags, optional linked repos, separately-deployable
components). Don't import remote ecosystem trivia.
#### Part 3 — Architectural blueprint
- Tech-stack summary (can reference the Part 1 table).
- C4-style diagrams as Mermaid: Level 1 system context, Level 2 containers,
Level 3 a representative request/component lifecycle.
- Layering and dependency rules (what may depend on what, and what enforces it).
- Cross-cutting concerns table: auth, config, logging, metrics/tracing, secrets,
error handling, feature flags — each with its location and evidence.
- Inferred Architectural Decision Records (reconstructed from code + docs).
- Governance & enforcement mechanisms (CI gates, codegen verification,
CODEOWNERS, review gates, compatibility rules).
- "How to add a feature" guide plus common pitfalls.
#### Subsystem deep-dives
Identify the 2-3 most complex or architecturally significant subsystems — the
parts a new engineer would most struggle with, such as an evaluation/scheduling
engine, a plugin loader pipeline, a state machine, or a rendering/migration
framework. For each, add a dedicated subsection covering its internal structure,
lifecycle or state machine, key types, and data flow, with local file+line
citations and a small Mermaid diagram where it clarifies the flow. This is what
separates a useful onboarding doc from a directory listing — spend real effort
here.
#### Confidence assessment
A table of the major claim areas rated **High / Inferred / Unverified**, so a
reader knows exactly which parts to trust outright and which to double-check.
#### Footnotes — local file citations
A list of the key local files the document relies on, each with a one-line note
on what it establishes.
### Conventions that make the document trustworthy
These are the habits that distinguish this skill's output from a generic
overview. They matter because the document's entire value is that a reader can
rely on it without re-deriving everything.
- **Cite every non-obvious claim** to a local path, with a line number where it
pins something specific (`pkg/server/server.go#L39-L41`). Relative paths from
the repo root keep links clickable.
- **Mark uncertainty honestly.** Use `[INFERRED]` for something you reasoned to
but didn't see stated, and `[UNVERIFIED]` for something you're repeating but
didn't confirm (e.g. a build-timing claim from a doc you didn't re-measure).
Honest gaps are more useful than false confidence.
- **Resolve contradictions, don't restate them.** If two sources disagree (say a
version literal in code vs. the manifest), go read the code, decide the real
answer, and label it `[Resolved contradiction]` with the explanation. Leaving
a reader to puzzle over a conflict is a failure mode.
- **Note compatibility and deploy-cadence rules** the repo enforces — separate
FE/BE PRs, bidirectional storage compatibility, additive-only protobuf changes
— because these are the rules a newcomer most easily breaks.
- **Prefer precise counts over vague ones.** "73 service packages", "89 workflow
files" (from a directory listing) reads as verified; "many services" reads as a
guess.
### Scope control
Keep the document grounded in the checkout. It's easy to drift outward into the
project's wider ecosystem (related products, README marketing, satellite repos)
— resist that unless it's visible on disk, and clearly label anything that comes
from outside the local tree. The reader asked for *this codebase*, documented
faithfully.
## Modernization mode
Generate a complete, actionable modernization plan for a legacy codebase. This
skill focuses on the forward-looking work — what to modernize, why, in what
order, and how — but it is **self-sufficient**: it ensures an architecture
document exists first, producing one via Documentation mode when needed.
**Assume dead-by-default.** People reach for modernization precisely because the
old stack is hard or impossible to upgrade — EOL runtimes, uncompilable native
modules, retired package mirrors, abandoned frameworks. So this skill does **not**
assume you can resurrect the legacy toolchain and stand up a fully-green CI gate
before touching anything. That "freeze-then-lift" approach is the *lucky* case,
not the default. Instead the skill runs a **time-boxed feasibility spike**, then
picks a migration strategy and a **safety strategy** matched to how alive the
system actually is. On a truly dead app, building a green legacy gate *is itself
a modernization project* — a circular trap this skill is designed to avoid.
Three ideas drive the whole plan and are introduced below: the **Testability
Milestone** (when — per component — the system can actually build, run, and pass
a test again), the **safety ladder** (the highest rung of regression safety
you can actually reach, with a downgrade treated as a blessed outcome, not a
failure), and the **CI Milestone** (which phase first stands up CI — and the
reminder that *enforcing* CI as a required check is a manual human step, not
something the agent can do).
### Prerequisites
This skill needs an understanding of the system's architecture before it can
plan. Resolve that as follows:
1. If an architecture document already exists — produced by **Documentation mode**
above, or a README / ARCHITECTURE.md the user points to, or enough
prior conversation context — use it and skip to the workflow below.
2. **If none exists, run the Documentation mode workflow above first** to
generate a cited architecture document, then continue **straight through**
to Phase 1 below in the same pass. Do not stop to ask the user to run it
separately, and do not pause for review between the two documents.
The result is two artifacts: the architecture document (the audited evidence
base) and this modernization plan (the forward-looking action set).
**Before planning, confirm a Commands & Verification Inventory exists.** Exit
criteria are only worth anything if they are *runnable*, so the plan must be able
to cite the project's canonical build / run / test / lint / typecheck / e2e /
contract commands and CI gate(s). Documentation mode produces this
inventory in Part 1; if you're working from a README or prior context that lacks
it, detect and record those commands yourself (per-ecosystem — npm/yarn/pnpm,
`make`, `just`, `cargo`, `go`, `poetry`/`tox`/`nox`, `gradle`/`mvn`, etc.) before
writing exit criteria. Never invent a command you haven't verified against the
task runner / manifests / CI config.
### Workflow
#### Phase 1: Assess Current State (from existing docs)
Read the architecture document and extract:
1. **Tech stack inventory** — languages, frameworks, runtimes, dependencies with
versions where visible
2. **Feature/domain map** — the major functional areas of the system
3. **Pain points already identified** — tech debt, concerns, deprecated deps,
architectural violations noted in the existing docs
4. **Deployment and infrastructure** — how it runs today
Do NOT re-read every source file. Trust the architecture doc. Only open specific
files if a modernization question requires verifying a detail (e.g., "is this
dependency actually used or just declared?").
#### Phase 2: Feasibility Spike, Strategy Fork & Safety Ladder
This is the pivot of the whole plan. **Do it before recommending a target
architecture or writing any phases.** Its job is to answer, quickly and honestly:
*how alive is this system, what migration shape fits, and how much regression
safety can we actually achieve?*
##### 2a. Run a time-boxed feasibility spike
Put a **hard time box** on it (e.g. one day). The spike's question is **NOT "can
we make CI green?"** — it is **"can we get this to run even *once* to capture its
behavior?"** Probe, per component / deployable unit:
- Does it **install** its dependencies today (ideally **from a committed
lockfile without hand-patching**)?
- Do **native/build steps** succeed on a **currently supported** toolchain?
- Does it **boot / start**?
- Can the **test runner execute at all**, and does **≥1 meaningful test pass**?
Record what you actually observed — including partial success (common in
monorepos: one service installs and tests green while another can't compile). Do
**not** sink two sprints resurrecting a corpse to discover it's unresurrectable.
When the time box expires, decide with the evidence you have.
##### 2b. Locate the Testability Milestone (per component)
**"Testable" is not a precondition you can satisfy on a dead app — for a dead app
it is an *output* of modernization, not an input.** So every plan must name, up
front, its **Testability Milestone**: the specific phase at which the system
(or a given component) first satisfies **all four** conditions at once:
1. Runs on a **supported** (non-EOL) runtime.
2. Dependencies install **from a lockfile without hand-patching**.
3. Native / build steps **succeed on the current toolchain**.
4. The **test runner executes and ≥1 meaningful test passes in CI**.
Assess this **per component** — as the reference Nylas run showed, a near-modern
cloud service can cross the line immediately while a legacy Electron client
doesn't cross it until several phases later. **This milestone is the single most
important marker in the plan.** State where it lands for each component, out loud.
##### 2c. Label every phase pre- or post-testability
The Testability Milestone splits the effort into two regimes with **different
safety rules**:
- **Pre-testability ("dark") regime:** the component can't be trusted to run.
Safety comes from **non-test** sources (see the safety ladder below).
**Requiring a CI test gate here is a category error** — you're demanding green
tests from something that isn't alive yet.
- **Post-testability ("lit") regime:** it builds and runs on a live, supported
stack. *Now* real CI, characterization, and e2e are achievable and worth the
investment. The classic green-gate belongs **here**.
**Rule: never require an automated test gate on a component before that component
crosses its own testability line.**
##### 2d. Choose the migration strategy — the A/B fork
The spike decides which of two shapes fits (this is a per-component call in a
monorepo):
- **(A) Freeze-then-lift.** Net the old app *as-is*, then upgrade under the net.
Requires the old app to be **resurrectable at acceptable cost** — i.e. it
*almost* runs. This is the traditional "characterization tests before you
change anything" path. **Opt-in, not the default.**
- **(B) Beachhead-then-expand (walking skeleton).** Don't net the corpse. Drive
the **thinnest possible end-to-end slice onto the modern stack** until it
builds, boots, and tests; then strangle the rest in, writing tests **on the new
stack** as you go. **This is the default for dead apps.** In strategy B, the
first phase is *"reach the Testability Milestone with the smallest slice,"* not
*"freeze the whole legacy toolchain."*
If a component **can't be built or run at all**, characterization tests on the
*old* stack are impossible by definition — invert the approach: **stop trying to
net the corpse and build the net on the *target* stack incrementally**, using the
old code/output as the reference oracle.
##### 2e. Pick the highest achievable rung on the safety ladder
Regression safety is a ladder, not a binary. Choose the **highest rung you can
actually reach** per component; **a downgrade to a lower rung is a blessed,
first-class outcome — not a failure — provided the residual risk is named.**
- **L4 — Full automated gate:** green lint + unit + characterization + e2e in CI.
- **L3 — Partial gate:** some suites green + lockfile + CI on the achievable
subset; the rest **quarantined** with a named list.
- **L2 — Characterization / golden-master only:** can't run in CI, but capture
I/O snapshots / behavioral diffs (manual is acceptable).
- **L1 — Reversibility-based:** no runnable tests; safety comes from small
reversible steps, strangler / parallel-run, a smoke checklist, and review.
- **L0 — No net possible:** treat as a spec-driven rewrite (old code = the spec)
or archive.
**Safety is not only tests.** There are at least five sources, and on dead apps
2–4 often outweigh 1:
1. **Tests** (characterization / unit / e2e) — strongest, often unachievable on
dead apps.
2. **Reversibility** — tiny commits, branch-per-change, trivial rollback.
3. **Isolation** — feature flags, strangler-fig, run old + new in parallel and
**diff outputs**.
4. **The running old system as an oracle** — record/replay real I/O to
characterize behavior without a test harness.
5. **Human review + domain knowledge.**
**Anchor safety at the behavioral *seams*, not the unit.** The durable,
stack-agnostic contracts of any app are its externally observable behaviors:
HTTP endpoints, DB schema/queries, file/wire formats, CLI output, protocols. Pin
*those* as golden-master / approval snapshots — **they survive the rewrite; unit
tests on dead legacy code get deleted the moment you replace the module.** Get an
**oracle**, ranked by what's available:
- **Best — it runs *somewhere*** (prod, a VM, an old container, even read-only),
**and you're allowed to use it**: record real I/O and replay it against the new
code. One successful capture beats a permanent green legacy CI. *(Do not assume
this rung is always available — a faithful third-party reimplementation or a
resurrected legacy binary may be off-limits by policy, licensing, or an
explicit decision to build "with only what we have." If so, skip to the
self-frozen rung.)*
- **Fallback — it doesn't run at all:** the old **source is the spec**;
supplement with prod logs, DB dumps, docs, tickets, and accept that
characterization tests get written **against the new implementation** to lock
it once verified correct.
- **Self-frozen golden master — no external reference exists or is permitted:**
when nothing trustworthy runs *and* you may not borrow an external oracle, the
**modernized component records its *own* golden master the moment it first runs**
(at its Testability Milestone), and every later phase diffs against that frozen
snapshot. This is a real, usable rung — but **name its residual risk out loud**:
it guarantees the *self-consistency of later refactors*, **not** the correctness
of the first boot (the snapshot is only as correct as the run that produced it).
Pair it with human review / spec cross-checks to bless that first run.
##### 2f. Feed an economic/oracle triage into the choice
Weigh **regression cost** when picking a rung: Is the app **in production**? Does
it have **real users**? Is the **old system still runnable** as a reference? An
abandoned app with zero users has near-zero regression cost — an expensive gate
there is **over-engineering**. A production system with users justifies a higher
rung and a real oracle.
##### 2g. Locate the CI Milestone (name the phase that stands up CI)
Just as the Testability Milestone names *when a component can first run and be
tested*, the **CI Milestone** names *when continuous integration is first stood
up* — and it must be **stated out loud in the roadmap, not buried in a phase
body.** A common failure of modernization plans is leaving the reader unable to
tell which phase introduces CI; name it explicitly.
**Rule: CI is stood up in the *first lit phase* — at or immediately after the
component crosses its Testability Milestone — never before.** CI cannot be green
on a component that cannot yet build/run, so wiring a CI *gate* during the dark
regime is the same category error as demanding a test gate there. (Trivial
scaffolding — a lint-only or build-only workflow — may appear earlier, but the
authoritative test gate lands at the CI Milestone.)
**CI is two distinct steps, and the second is human-only** — call both out:
1. **Author the CI workflow file** (e.g. `.github/workflows/*.yml`, `.gitlab-ci.yml`,
Azure Pipelines) that runs the gate. **An agent can do this.**
2. **Make that workflow an *enforced* gate** — a **required status check /
branch-protection rule / merge-request approval rule**. This is a manual
platform-UI / admin step (GitHub → Settings → Branches; GitLab protected
branches + MR settings; etc.) that **an agent cannot perform.** Until a human
configures it, CI *runs* on PRs but does **not** *block* merges.
Because step 2 is outside the agent's reach, **every plan that stands up CI must
emit it as an explicit user action item** (in the phase's exit criteria and in
§9 Open questions / decisions needed from stakeholders), so the reader knows the
gate is not self-enforcing until they turn it on.
**Output of Phase 2:** for each component — the spike result, the chosen strategy
(A or B), the located Testability Milestone, the pre/post label, and the target
safety-ladder rung with any residual risk named — **plus the plan-wide CI
Milestone** (which phase stands up CI) and the reminder that enforcing it is a
manual human step. Everything downstream depends on these.
#### Phase 2.5: Red-team every phase against the hazard catalog (mandatory)
The strategic scaffolding above (testability, safety ladder, CI milestone) is
necessary but **not sufficient**. Modernization plans also fail on *tactical,
ecosystem-predictable* hazards — an incomplete quarantine set, a forgotten
namespace codemod, a runtime bump that leaves the base images behind, a stateful
data-store major treated as an image bump, an edge rewrite that drops the
anonymous route class. These are so recurring that they have their own catalog:
**`references/migration-hazards.md`** (H1–H8).
**Rule: before any phase is implemented, red-team its plan against every hazard
in `references/migration-hazards.md`.** For each hazard, ask "does this phase
trigger it?", run the hazard's detection probe against the real repo, and fold
its plan action into the phase's tasks/exit criteria **before** writing code. A
hazard caught in planning is a task; caught in review it's rework; caught in prod
it's an incident. Record hazards you checked and **cleared**, not just the ones
that fired — a silent skip is indistinguishable from a miss.
This is the institutionalized form of an independent-critic pass. Do it yourself
by walking the catalog, and — where an independent second opinion is available
(e.g. a rubber-duck / critique agent) — use it: on the reference PiggyMetrics run
such a pass caught a **blocking plan gap in every single phase**, and each gap
was an instance of an H1–H8 class. Bake the outcome into each phase's
"Decisions made" and exit criteria so the executing agent inherits the cleared
checklist rather than re-discovering the hazard.
#### Phase 3: Recommend Target Architecture
**Decision framework — always evaluate in this order:**
For each component/dependency, work through these levels from least-disruptive to
most-disruptive. Stop at the first level that solves the problem:
1. **Upgrade in place** — Can you bump the major version and fix breakages?
(e.g., Node 14→22, Python 2→3, React 16→19, Rails 5→7). This is the default
answer. Only reject it if the upgrade path is officially unsupported, the
breaking changes are so extensive they exceed rewrite cost, or the framework
itself is abandoned/EOL.
2. **Swap the dependency** — If the specific library is dead but the pattern is
fine, can you swap to a maintained alternative with the same interface shape?
(e.g., Moment.js → date-fns, Request → got/fetch, CoffeeScript → TypeScript
with decaffeinate). Prefer drop-in or mechanical migration tools when they
exist.
3. **Wrap/adapt (Strangler Fig)** — If the component's interface is sound but
internals are unmaintainable, can you put a clean interface in front and
incrementally replace internals behind it? This works when coupling is
manageable and the system can run with old and new coexisting.
4. **Rewrite** — Only when: the framework is abandoned with no upgrade path, the
architecture fundamentally cannot support required new capabilities (e.g.,
synchronous-only design that must become real-time), or honest estimation shows
upgrade cost exceeds rewrite cost. Require explicit justification for every
rewrite recommendation — "it's old" is not sufficient.
5. **Remove** — Dead code, features with zero usage, deprecated capabilities
superseded by other systems. Verify usage claims before recommending removal.
**Bias toward conservatism.** The cheapest migration is the one you don't do.
Every level of disruption adds risk, timeline, and cost. A working system on an
older framework is better than a half-finished rewrite on a new one.
**Mechanical-migration riders (apply whenever a recommendation is an upgrade,
swap, or removal).** These are the parts of a target-architecture decision that
first-draft plans routinely drop; each maps to a hazard class in
`references/migration-hazards.md`:
- **Transitive-quarantine completeness (H1).** When removing/cutting over a whole
dependency family, grep the dead artifact across **all** manifests and list the
*full* set of dependents that must move or be quarantined — not the subset you
first thought of. State the post-cutover build target explicitly.
- **Framework-major codemods (H2).** A **major** bump carries mechanical breaking
changes independent of your logic — namespace renames, removed deprecated APIs,
a changed **test engine**, changed config keys. Enumerate each as its own task
and prefer the ecosystem's automated **recipe/codemod tool** (OpenRewrite,
jscodeshift/react-codemod, `2to3`/`pyupgrade`, etc.) over hand-editing on large
trees. Don't forget the test-framework migration — it is the most-forgotten one.
- **Runtime↔deployment lockstep (H3).** If a recommendation bumps the
language/runtime **major...
© github · MIT · github/awesome-copilot