# Website Migration Redirect Map Benchmark

**Worked synthetic benchmark; not a production crawl or traffic forecast.**

- Fixture set: `website-migration-benchmark-20260717`
- Engine SHA-256: `3f08e9ba6b24fb9a32843e6b81015da3c77154113a266882a54fc96f5d6cd805`
- Fixture SHA-256: `b6119f07bea5376a009f57eac48826f0472cd8d5dda637c1abc82a8d1c71aa17`
- Scenarios: 26 (24 real engine runs; 2 fail-closed capability boundaries)
- Result: PASS

## Reproduce

```sh
node scripts/test_website_migration_benchmark_20260717.js
```

## Scenario results

| Scenario | Category | Method | Decision | Risks | Result |
|---|---|---|---|---|---|
| exact-one-to-one | mapping | engine_run | ready_for_staged_redirect_qa | none | PASS |
| prefix-directory-move | mapping | engine_run | review_risky_rows_before_staged_redirect_qa | medium_confidence_review | PASS |
| ambiguous-near-tie | ambiguity | engine_run | review_risky_rows_before_staged_redirect_qa | candidate_collision, medium_confidence_review | PASS |
| automatic-target-collision | collision | engine_run | review_risky_rows_before_staged_redirect_qa | duplicate_target, target_already_assigned | PASS |
| manual-duplicate-target | collision | engine_run | review_risky_rows_before_staged_redirect_qa | duplicate_target | PASS |
| redirect-chain | graph | engine_run | review_risky_rows_before_staged_redirect_qa | redirect_chain, target_not_in_new_inventory | PASS |
| redirect-loop | graph | engine_run | review_risky_rows_before_staged_redirect_qa | redirect_loop, target_not_in_new_inventory | PASS |
| meaningful-query-loss | query | engine_run | review_risky_rows_before_staged_redirect_qa | query_parameter_loss, query_specific_redirect_review | PASS |
| query-preserved-still-reviewed | query | engine_run | review_risky_rows_before_staged_redirect_qa | query_specific_redirect_review | PASS |
| tracking-query-normalization | query | engine_run | review_risky_rows_before_staged_redirect_qa | query_specific_redirect_review | PASS |
| path-case-change | normalization | engine_run | review_risky_rows_before_staged_redirect_qa | medium_confidence_review | PASS |
| trailing-slash-preserved | normalization | engine_run | ready_for_staged_redirect_qa | none | PASS |
| double-slash-blocked | normalization | engine_run | review_risky_rows_before_staged_redirect_qa | unsupported_double_slash_path | PASS |
| excluded-removed-url | coverage | engine_run | review_risky_rows_before_staged_redirect_qa | orphan_source | PASS |
| excluded-override-source | coverage | engine_run | ready_for_staged_redirect_qa | none | PASS |
| no-destination | coverage | engine_run | review_risky_rows_before_staged_redirect_qa | orphan_source | PASS |
| unexpected-cross-domain | origin | engine_run | review_risky_rows_before_staged_redirect_qa | target_not_in_new_inventory, unexpected_cross_domain_target | PASS |
| same-origin-target-not-in-inventory | coverage | engine_run | review_risky_rows_before_staged_redirect_qa | target_not_in_new_inventory | PASS |
| target-is-redirect | runtime-evidence | engine_run | review_risky_rows_before_staged_redirect_qa | target_redirect_status | PASS |
| target-is-error | runtime-evidence | engine_run | review_risky_rows_before_staged_redirect_qa | target_http_error_status | PASS |
| invalid-override-status | input-validation | engine_run | ready_for_staged_redirect_qa | none | PASS |
| normalized-override-ambiguity | ambiguity | engine_run | review_risky_rows_before_staged_redirect_qa | duplicate_target, query_specific_redirect_review, target_already_assigned | PASS |
| unsafe-config-metacharacters | security | engine_run | review_risky_rows_before_staged_redirect_qa | target_not_in_new_inventory, unsupported_config_metacharacter | PASS |
| non-301-adapter-boundary | adapter | engine_run | ready_for_staged_redirect_qa | none | PASS |
| rollback-baseline-missing | rollback | capability_boundary | INDETERMINATE | rollback_not_evaluated | PASS |
| rollback-artifact-not-generated | rollback | capability_boundary | INDETERMINATE | rollback_not_evaluated | PASS |

## Method

Each engine-run case is entered through the public renderer UI in headless Chromium. The harness reads the generated receipt and redirect ledger, recomputes every artifact SHA-256, verifies the receipt core, and proves that blocked rows do not leak into the Cloudflare adapter. The 308 case also proves that Webflow's 301-only adapter excludes non-301 rows.

Rollback is not simulated. The present engine has no rollback-baseline input and does not capture a rollback artifact, so both rollback cases are explicitly INDETERMINATE.

## Limits

- Synthetic `.test` URLs only; no DNS, origin, CDN, Search Console, analytics or server-log access.
- String and URL-graph checks do not prove content equivalence, SEO outcomes or deployment correctness.
- Browser-run PASS means the checked policy assertions passed for this exact engine and fixture hash.
- Generated redirect adapters still require platform syntax validation, staging crawl, owner approval and a separately captured rollback packet.

## Primary sources

- https://developers.google.com/search/docs/crawling-indexing/site-move-with-url-changes
- https://developers.google.com/search/docs/crawling-indexing/301-redirects
- https://developers.google.com/search/docs/crawling-indexing/consolidate-duplicate-urls
- https://www.rfc-editor.org/rfc/rfc9110.html#section-15.4
- https://developers.cloudflare.com/rules/url-forwarding/bulk-redirects/
- https://nginx.org/en/docs/http/ngx_http_rewrite_module.html
- https://httpd.apache.org/docs/2.4/en/mod/mod_alias.html
