---
name: redirect_map_preflight
description: "Validates a redirect map before a site move or redesign launch: coverage of every legacy URL, duplicate and conflicting sources, self-redirects, chains, loops, status code choices (301 vs 302, 308, 307, 404, 410), and targets that return errors. Ships a tested map validator and chain tracer. Use when preparing, reviewing, or fixing a redirect map, migration spreadsheet, or server redirect config before launch."
---

# Redirect Map Preflight

## Purpose

Catch redirect map errors while the old site is still live and fixing them costs an edit, not lost traffic. A redirect map is a graph, and most of its failures are graph failures: a source listed twice with two answers, a target that is itself a source, two URLs pointing at each other, a legacy URL with no row at all. Checking rows one at a time in a spreadsheet misses all of them, because each row looks fine on its own. This skill checks the map as a whole, orders the fixes by traffic, and leaves a cleaned map plus a trace for any single URL. It covers the pre-launch check only. Deploying the redirects and monitoring the move are separate jobs, and this skill says where its proof ends.

## Workflow

1. Build the legacy inventory first, before touching the map. Pull old URLs from the sitemap, the CMS listing, server logs or analytics for the URLs that get traffic, and the links report for pages other sites point at. Include images, videos, PDFs, and other hosted files. Google site-move guidance names the same sources. Save one URL per line. This list is the coverage contract: a map that only covers the URLs someone remembered is not a map.
2. Put the map in the validator format. CSV with header `source,target,status,traffic`. Source is the old URL or path, target is the new one, status is the intended code, traffic is visits or clicks in a lookback window that covers seasonal peaks. Leave target empty only for an intentional 404 or 410 row. Pattern-based rules (one slug prefix to another) get expanded to concrete rows for checking, or listed and reviewed separately. Do not let a pattern hide inside the row count unexamined.
3. Run the validator. `python3 scripts/redirect_check.py MAP.csv --inventory INVENTORY.txt` from this skill folder. It reports duplicate conflicting sources, exact duplicates, self-redirects, loops, chains with the full hop path, chains ending at a 404 or 410 row, missing targets, malformed URLs, invalid statuses, temporary statuses, bulk-to-one-target groups, and every inventory URL with no row. Exit code 1 means at least one error. Use `--format json` when another tool consumes the findings.
4. Trace any URL a stakeholder asks about. `python3 scripts/redirect_check.py MAP.csv --trace /old-path` prints the hop sequence and outcome for that one source. Use it in review meetings instead of reading rows aloud.
5. Fix in the order the tool prints: errors first, then highest traffic first. The order matters because review time runs out. A loop on a 5,000 visit page is a launch blocker. A chain on a 12 visit page is a cleanup item. For each finding, the fix patterns are in the next section.
6. Choose each status code from intent. Read `references/status-codes.md`. Permanent move gets 301, or 308 when the request method must survive. Temporary move gets 302, or 307 the same way. Gone with no equivalent gets a 404 or 410 row, not a redirect to the homepage or a category page the visitor did not ask for.
7. Check targets against a live environment when one exists. On staging, or after deploy on production, run the validator again with `--check-targets`. It fetches each distinct http or https target once, without following redirects, and flags targets returning 4xx or 5xx (ERROR TARGET_ERROR_STATUS), targets that redirect again (WARNING, the deployed chain is longer than the map shows), and targets that cannot be reached at all. Path-only targets cannot be live checked, so spot-check the highest traffic ones by hand against the staging host.
8. Re-run until clean, then freeze the map. Zero errors is the launch bar. Warnings may ship only with a named reason each, written next to the row: a genuinely temporary redirect, a chain that a platform constraint forces. Version the frozen map, and treat any late edit as a new preflight, not a tweak.
9. Hand off with the retention note. Google guidance is to keep migration redirects in place for as long as possible, generally at least 1 year. Put that date, and who owns the redirects after launch, in the handoff. A clean map that someone deletes in month two still fails.

## Fix patterns

- Duplicate conflicting source: decide the one real destination by opening the candidate targets on the new site. Keep one row. Conflicts usually come from two teams mapping the same section, or an old export merged with a new one.
- Self-redirect: the page did not move, or the target was pasted from the source column. Delete the row or correct the target. Watch trailing slash and case variants, they are the same trap.
- Loop: two or more URLs pointing around a circle, often a pair swapped during editing (A to B written where B to A was meant) or a protocol and host rule fighting a path rule. Break the circle by pointing every member at the final destination outside it.
- Chain: the target of one row is the source of another. Flatten by pointing every earlier source straight at the final destination. Keep the intermediate rows themselves if their URLs may be visited directly, but point them at the final destination too. Google advises redirecting to the final destination directly, keeping chains ideally to 3 hops and fewer than 5 when a chain cannot be avoided, and notes Googlebot follows up to 10 hops. Treat 10 as a ceiling that exists, never as a budget to spend. Each hop is another request, another delay, and another place for the path to break.
- Chain ending at a removal: a redirect that lands on a URL the map marks 404 or 410. Either the landing page is not really gone (fix its row) or the source needs a real equivalent (fix the source row). Never leave a redirect whose destination is an error on purpose.
- Missing coverage: the inventory URL gets a row. Redirect to the closest equivalent page, meaning the page a visitor who wanted the old one would want. If none exists, an explicit 404 or 410 row. A missing row found after launch means that URL serves whatever the new site happens to return, which nobody chose.
- Temporary status on a permanent move: change it to 301 or 308. This is the most common quiet failure in migration maps, often inherited from a CMS default or a staging rule copied into the launch config.
- Many sources to one target: the validator flags 10 or more sources sharing a target. Review each one. A section genuinely consolidated into one strong page is fine. Fifty unrelated posts pointed at the homepage is a decision to strand those visitors, and it should be made on purpose or not at all.

## Output Contract

- The validated map CSV, frozen and versioned, with traffic on every row that has any.
- The validator output for the final run: rows checked, error and warning counts, and the full finding list for any warning that ships with its written reason.
- A coverage statement: inventory size, how many inventory URLs redirect, how many are intentional 404 or 410 rows, and confirmation that the count of unaccounted URLs is zero.
- A trace for any URL a stakeholder disputed, showing hop count before and after flattening.
- The live-check result when a staging or production environment existed: which targets were fetched, and every target error found, or a plain statement that targets were path-only and which high traffic rows were spot-checked by hand.
- The retention note: keep redirects at least 1 year, owner named.
- A worked before and after example lives in `references/worked-example.md`: a 13 row broken map with 8 errors and 2 warnings, cleaned to 0 and 0 with the same validator.

## Operating Rules

1. Validate the map as a graph, never row by row. Duplicates, chains, and loops are invisible in single-row review.
2. No launch with errors open. A warning ships only with a written reason tied to that row.
3. Status code follows intent, not habit and not whichever code a plugin emitted. Permanent and temporary are different promises to search engines about which URL to show.
4. The closest equivalent page is the target standard. Homepage and section index targets for unrelated old pages need explicit justification per row group.
5. An intentional 404 or 410 is a valid map decision and beats a dishonest redirect. It must be an explicit row, not an omission.
6. Offline validation proves the map is internally consistent. It does not prove the server will do what the map says. Config syntax, rule order, and platform rewrites run after this check, and the post-deploy live check is what catches them.
7. Keep the inventory honest. If a URL source was skipped (log retention too short, a subsite nobody listed), say so in the coverage statement instead of claiming full coverage.
8. Do not invent performance numbers for chains. The documented costs are extra requests, added latency, crawl effort, and breakage risk. That is enough reason to flatten them.
