Definition of Done — item 7
This document defines how "done" is measured for item 7: the scoring method, the thresholds, the evidence it is computed from, and the reporting model it produces. It also states where each property currently sits against that standard. The measurement is not proposed — it has already been run once, as the pre-migration baseline.
That row is the acceptance statement. It is the sentence PADI will hold the SEO workstream against when deciding whether this part of the programme is complete, so the rest of this page sets out what each clause in it means in practice, how it gets tested, and when.
Executive summary
Content performance and cannibalization audits are complete across all three migrating domains. Those audits produced the migration mapping sheet, PADI returned keep / retire / merge / migrate decisions, and we re-ran technical audits scoped to exactly the pages surviving the move. There are three guardrails documents, one per property. blog.padi.com is complete with its open questions substantially closed with the PADI marketing team, pros-blog.padi.com is built to a deeper 41-tab structure, and padi.com closes next week. After that, item 7 moves from audit work to acceptance testing against the Drupal templates.
Measurement model
The pre-migration crawl is the baseline. The identical crawl re-run after migration is the score. Every tab in the guardrails workbooks is a defect class with a count against it, so the same checks that told us what was wrong before the move tell us what is right after it. On top of that sits an Organic Recovery Index measured against frozen performance data. We are not inventing a measurement framework for this — the instrument already exists and has already been run once.
Four steps, applied identically to every property and every run. Defined once here so that a score produced in November means the same thing as a score produced in February.
| Step | Operation | Definition |
|---|---|---|
| 1 | Defect rate per tab | URLs flagged in the tab, divided by the URLs in scope for that specific check. A rate rather than a raw count, so properties of different sizes are comparable and so growth in the URL set does not distort the score. |
| 2 | Tab score | 100 if the defect rate is at or below the tab's pass threshold, 50 if between pass and fail, 0 if at or above the fail threshold. Thresholds are set once per tab and frozen for the duration of the programme. |
| 3 | Family score | Mean of the tab scores within that family. Reported alongside the composite, because a family failing behind a healthy composite is the failure mode this model exists to prevent. |
| 4 | Composite | Weighted sum of the four family scores: Redirects 30, Decisions 20, Technical 35, Schema 15. One number per property, per run. |
Some defects cannot be averaged away. A single occurrence in any of these is a fail regardless of the composite score: a backlink-protected URL failing to resolve, a destination collision, a keep URL absent from the live crawl, an unresolved merge, a 4xx on the keep set, a noindex failure on the 75 unlisted pages, or a schema required-field error. Scoring 94 elsewhere does not make private editorial content being publicly indexed acceptable.
| Family | Weight | What the post-migration re-run proves | Pass threshold |
|---|---|---|---|
| A · Redirects | 30 | Every rule in the redirect file fired as written. Holds preserved, collisions resolved, locale codes mapped to the destination architecture rather than the legacy one. | All 1,146 backlink-protected URLs resolve single-hop. Zero destination collisions. Zero chains beyond one hop. |
| B · Decisions | 20 | Each decision was executed as decided. Retired content unpublished but recoverable, keeps live and reachable, merges resolved to one surviving URL, nothing crawled that is absent from the sheet. | Zero decision differences. Zero merges unresolved. Zero keep URLs missing from the live crawl. |
| C · Technical | 35 | Response codes, canonicals, hreflang return links, robots directives, metadata and heading structure on the migrated set. This is the largest family because it is where regression hides. | Defect count at or below baseline in every tab. Zero 4xx and zero broken inlinks on the keep set. |
| D · Schema | 15 | Structured data present at or above the pre-migration entity graph, with language codes correct. The single biggest regression risk in this migration. | Schema coverage at or above baseline. Zero required-field errors. Language codes match the agreed locale map. |
First, the crawl configuration must be identical pre and post — same user agent, same rendering mode, same depth, same URL set. A cleaner-looking score produced by a narrower crawl is not an improvement. Second, the post-migration crawl runs against the migrated equivalents of the same pages, not against whatever the new site happens to expose, otherwise retired content quietly flatters the result.
| Metric | Source | Measured | Done threshold |
|---|---|---|---|
| Indexed page count | GSC | Day 30, 45, 90 | 95 or above by day 30 |
| Organic clicks | GSC | Day 30, 45, 90 | 95 or above by day 90 |
| Impressions | GSC | Day 30, 45, 90 | 95 or above by day 90 |
| Average position, priority clusters | GSC | Day 30, 45, 90 | No worse than one position below baseline |
| Organic sessions | GA4 | Day 30, 45, 90 | 95 or above by day 90 |
| Ranking keyword count | SEMrush, directional only | Day 30, 45, 90 | 95 or above by day 90, read as trend not absolute |
| Scorecard element | What it shows |
|---|---|
| Composite and band | One number and its Pass, Conditional or Fail band, against the same number from the previous run |
| Four family scores | Where the composite comes from, so a weak family cannot hide inside a healthy total |
| Blocking status | Clear or not clear, with the specific defect named if not |
| Movement since baseline | Tab-level deltas, largest movements first, both directions |
| Open remediation | Item, owner, agreed fix window, and whether it has slipped |
| Recovery Index | Post-launch runs only. Outcome metrics against the frozen baseline |
Thresholds and weights are fixed at Gate 1 and versioned. Changing either mid-programme invalidates comparison against the baseline, so any change is a documented decision with PADI rather than a quiet adjustment. Scores are computed by the SEO workstream from the guardrails workbooks, and the scorecard is published to the Looker dashboard so PADI can read the current position without waiting for a report.
Gate 1 requires the pre-migration crawl complete and the baseline frozen for all three properties. Gate 2 and Gate 3 require a Health Score of 90 or above per property, with no single family below 80 and zero blocking defects in the A and B families. Gate 4 requires a Recovery Index of 95 or above with a positive trajectory at day 90. Item 7 is declared complete when all four hold, per property, not before.
The score is not purely self-reported. SEMrush Site Health and GSC index coverage run alongside it as independent corroboration, so the composite can be sanity-checked against third-party measurement rather than taken on trust. Core Web Vitals thresholds are contracted in the SOW and are scored separately, since they sit under the performance row rather than this one.
How we got here
Each stage exists because the one before it changed what the next one needed to look at. The order matters: auditing before decisions produces findings that expire.
Complete across the estate, then superseded. Platform and content changes after delivery made the page-level findings stale. It still set the scope and the known-risk register.
SupersededPerformance and overlap analysis across padi.com, blog.padi.com and pros-blog.padi.com. 29,398 queries analysed, 1,502 flagged as merger risk.
Complete · 3 domainsBuilt from the audit output. Keep, retire, merge, migrate per URL, enriched with SEO and AEO performance so decisions are made on evidence rather than instinct.
Built and sharedWith decisions returned, technical audits re-run against only the pages being kept, merged or migrated. Output is the pre-migration guardrails package.
blog.padi.com 2 close next weekSpecs handed to engineering, template-level acceptance testing, cutover validation and a 45 to 90 day post-launch stability window against the pre-migration benchmark.
Specs issuedIt was accurate when delivered. Content was then added, removed and restructured, and the migration decisions changed which pages are even in scope. Re-auditing against the surviving URL set is what makes the findings actionable at build time, rather than a document that describes a site that no longer exists.
Breaking down item 7
The DoD line reads as one row. In practice it closes in six places, at three different gates. Stating the test up front is what stops "SEO signed off" becoming a subjective conversation at launch.
Every legacy URL resolves to a deliberate destination. No chains, no loops, no silent 404s on pages carrying traffic or links.
PADI has confirmed titles and descriptions migrate as-is. No bulk rewriting during migration. The 151 genuine defects are being fixed manually in WordPress before the move.
The blog emits a full entity graph across roughly 9,000 articles. padi.com interior pages currently emit none. Migrating into the weaker template is a regression risk, not a neutral move.
Canonicals, hreflang, robots directives and sitemaps. Two live constraints: 75 pages must stay unlisted but URL-accessible, and three locale codes change across 2,008 URLs.
Consolidated content must not arrive orphaned. Canonical ownership per query cluster resolves the cannibalization the audit surfaced.
Content must be reachable by search and AI crawlers without JavaScript execution. 519 French and Korean pages were returning server errors to crawlers while rendering normally in a browser; PADI has deployed a fix.
Status by domain
| Stage | blog.padi.com | pros-blog.padi.com | padi.com |
|---|---|---|---|
| Content performance audit | Complete | Complete | Complete |
| Cannibalization analysis | Complete | Complete | Complete |
| Migration mapping sheet | Decisions returned | In progress | Inventory in progress |
| Scoped technical re-audit | Complete · 30 tabs | Complete · 41 tabs | In progress |
| Guardrails package issued | 5 docs · 2 workbooks | 41 tabs | Closing next week |
| Open questions closed with PADI | Substantially · 3 open | Follows package | Follows package |
Evidence base
The technical audit is a crawl of exactly the URL set PADI has decided to keep, with every error class listed and documented in its own tab. Seventy-one validation tabs exist across the two completed workbooks. Every migration decision traces back to a named tab, which is what makes the redirect map defensible rather than assembled.
| Family | Covers | Tabs |
|---|---|---|
| A · Redirects | Redirect execution file | A1 Redirect File · A2 Manual Destinations |
| B · Decisions | Treatment logic per URL | B1 Retire with traffic · B2 Retire to hub · B3 Retire no destination · B4 Keep but 404 today · B5 Keep no destination · B6 Already redirecting · B7 Merge NA Archive · B8 Locale code map · B9 Proposed treatment · B10 Treatment summary |
| C · Technical | Crawl findings on the keep set | C1 Internal All · C2 Redirect Chains · C3 Noindex · C4 Canonicalised · C5 Hreflang Non-200 · C6 Hreflang Missing Return · C7 Inlinks Broken · C8 Titles Duplicate · C9 Titles Same as H1 · C10 Meta Desc Duplicate · C11 Meta Desc Missing · C12 H1 Missing · C13 H1 Duplicate · C14 H1 Multiple |
| D · Schema | Structured data baseline | D1 Schema Baseline |
| Family | Covers | Tabs |
|---|---|---|
| A · Redirects | Redirect execution and conflict detection | A1 Redirect File · A2 Redirect Holds · A3 Retire with Signal · A4 Destination Collisions · A5 Locale Code Map |
| B · Decisions | Reconciling the decision sheet against what the crawl actually found | B1 Decision Differences · B2 Merge Unresolved · B3 Retire with Clicks · B4 Retire with Backlinks · B5 Status Private · B6 Status Draft Pending · B7 Stale Keep Content · B8 Cannibalization Flagged · B9 Crawled Not In Sheet · B10 Keep Not Crawled |
| C · Technical | Crawl findings on the keep set | C1 Internal All · C2 Response 3xx · C3 Response 4xx · C4 Redirect Chains · C5 Broken Inlinks · C6 Noindex · C7 Canonicalised · C8 Canonical Missing · C9 Hreflang Return Links · C10 Titles Duplicate · C11 Titles Same as H1 · C12 Titles Over Length · C13 Meta Desc Duplicate · C14 Meta Desc Missing · C15 Meta Desc Over Length · C16 H1 Missing · C17 H1 Duplicate · C18 H1 Multiple · C19 Pagination · C20 Protocol · C21 Blocked by Robots · C22 All Inlinks |
| D · Schema | Structured data and language integrity | D1 Schema Parity · D2 Language Codes |
The third document covers padi.com and follows the same four families. Alongside each workbook: guardrails overview, developer handoff, template and metadata specification, technical crawl findings, and schema parity specification. A further workbook covers 1,146 backlink-protected URLs and 34 redirect conflicts.
It was built second and it is materially better: response codes split by class, decision reconciliation that catches URLs crawled but absent from the sheet and the reverse, destination collision detection, and language codes checked separately from schema. Adopting it as the common post-migration structure across all three properties makes the scores directly comparable, which matters when we are reporting one number per property to PADI rather than three differently-derived ones.
Closed with PADI
PADI's latest response resolved the majority of the outstanding migration questions. These are locked and feeding into the redirect map and template specs.
| Question | Confirmed position | Effect on our work |
|---|---|---|
| Russian language scope | Russian stays in the migration. PADI supports the language, not the region. Content remains available to Russian speakers outside blocked markets. | Reverses the earlier out-of-scope position. Russian URLs return to the mapping and hreflang set. |
| Language variant mapping | /es/ maps to Latin American Spanish, /fr/ to French, /pt-br/ to Brazilian Portuguese. No duplication across variants. Polish exists only on pros-blog. | Locale map finalised. Castilian, Canadian French and European Portuguese deferred to future business need. |
| Archive versus retire | Inconsistent labelling. Everything marked Archive is treated as Retire. | Treatment categories collapse from four to three. |
| Merge handling | Merges completed in WordPress before migration. One surviving URL per entry at cutover. | No merge logic required in Drupal. Timing dependency on PADI, needed by end of October. |
| Keep pages already redirecting | Preserve the original URL and its redirect. Where no destination is identified, redirect to the blog homepage. | Established traffic paths preserved rather than severed. |
| Canonicals on translated pages | Cross-language canonicals were unintentional. Drupal default corrects them to self-referencing. | Tab C4 resolves at template level, no manual remediation. |
| Metadata treatment | Migrate existing titles and descriptions unchanged. No bulk edits on length or H1-match grounds. PADI fixes 151 genuine defects manually. | Metadata optimization removed from migration scope. Deferred to a performance-led project. |
With bulk metadata work deferred, the DoD test for metadata is parity, not improvement. That is the right call for migration safety, and it should be recorded as such so nobody later reads flat metadata performance post-launch as a delivery gap. Optimization needs query-level performance data behind it, and that sits in a separate scope.
Open items
| Item | Owner | Priority | Risk if unresolved |
|---|---|---|---|
| Per-page noindex in Drupal 75 unlisted pages must stay unlisted but remain URL-accessible |
Axelerant engineering | High | Intentionally private editorial content becomes publicly indexed at launch. This cannot be solved in WordPress beforehand; it is a Drupal capability requirement. |
| Default destination for retired URLs 2,850 URLs |
SEO with PADI confirmation | High | Redirect file cannot be finalised. Unmapped retirements become 404s carrying live traffic and links. |
| French and Korean server errors 519 URLs, fix deployed by PADI |
Axelerant SEO, recrawl | High | Index loss continues if the fix is partial. Recrawl scheduled to confirm and close. |
| Guardrails packages for pros-blog.padi.com and padi.com In progress, closing next week |
Axelerant SEO | High | Not blocking today, but these must land before the redirect file can be treated as complete across all three properties. Slippage here compresses the decision window with PADI. |
| Blog sitemap index never submitted to GSC | Shared | Medium | No submitted baseline to measure discovery and recovery against post-launch. |
| padi.com interior pages emit no JSON-LD | Axelerant engineering | Medium | Blog content loses its existing entity graph on arrival. A schema regression disguised as a neutral migration. |
| Locale code changes /cn/ to /zh-cn/, /jp/ to /ja/, /tw/ to /zh-tw/ across 2,008 URLs |
Shared | Medium | Redirect and hreflang rework required. Now compounded by Russian returning to scope. |
| Canonical ownership per query cluster | PADI content team | Medium | Cross-domain cannibalization becomes internal cannibalization, which is harder to diagnose after the fact. |
| Server-side rendering confirmation | Drupal architecture | Medium | Content dependent on JavaScript execution is unreliable for AI crawlers, undermining the discoverability half of item 7. |
Path to done
Item 7 cannot close at a single moment. Half of it is validated before the build, half only exists once templates render. Treating it as one launch-day checkbox is how migrations lose visibility quietly.
Any platform migration produces temporary organic fluctuation, typically settling across 45 to 90 days. That is expected behaviour, not a failure signal. It is also why the pre-migration benchmark matters: without it there is no way to separate normal recovery from a structural problem, and the conversation post-launch becomes opinion rather than evidence.
Testing schedule
Testing is not a single pass before launch. It runs continuously from the first Drupal templates through to ninety days after cutover, because different criteria only become testable at different points. Windows below are anchored to the SOW delivery dates and need confirming against the live sprint plan.
| Test | Window | Environment | Evidence produced |
|---|---|---|---|
| Guardrails completion padi.com |
Next week | Live padi.com | Third guardrails document, completing the set of three |
| Server error recheck 519 French and Korean URLs |
Immediate | Live blog.padi.com | Recrawl result confirming whether PADI's fix cleared all errors |
| Pre-migration benchmark freeze | End of October | GSC, GA4, SEMrush | Frozen performance baseline. Without this there is nothing to measure recovery against |
| Template acceptance testing | Per sprint, through build | Development and staging | Per-template pass or fail on metadata, canonical, hreflang, schema and per-page noindex |
| Redirect dry run | UAT window | UAT environment | Full legacy URL list crawled against staged rules. Chains, loops and unmapped 404s surfaced before they are live |
| Full staging crawl | UAT window | UAT environment | Orphan report, internal link integrity, schema validation, sitemap generation check |
| Cutover validation | Launch day, first hours | Production | Live crawl of the legacy URL set, 1,146 backlink-protected URLs verified, robots.txt and sitemap submission confirmed |
| Guardrails re-crawl Identical config, all three properties |
Launch, then day 30 | Production | Post-migration defect counts per tab, scored against the pre-migration baseline. This is the Health Score. |
| Post-launch monitoring | Day 1, 7, 30, 45, 90 | Production, GSC, GA4 | Index coverage, ranking stability against benchmark, crawl error trend, cannibalization check inside padi.com |
The single highest-value test in this list is crawling the full legacy URL set against staged redirect rules before launch, not after. Every migration problem that is expensive to fix is cheap to catch at that point. If the UAT window compresses, this is the test to protect.
Sharing cadence
Nothing in this workstream is held back to a single launch report. Each gate produces evidence that goes to PADI as it is generated, so decisions are made with the data in front of everyone rather than after the fact.
| Output | Shared | Purpose |
|---|---|---|
| This status view | At the DoD review | Agree what item 7 means, which criteria close at which gate, and who owns each open item |
| Guardrails packages pros-blog.padi.com and padi.com |
Next week | Complete the evidence base across all three migrating properties |
| Final redirect file and template specs | Gate 1, end of October | Sign-off artefact. Once accepted, the redirect map is locked for build |
| Sprint acceptance results | In each sprint demo | SEO pass or fail per template, visible as the build happens rather than at UAT |
| UAT test report | End of the UAT window | Redirect dry run and staging crawl results, with any go or no-go concerns stated plainly |
| Cutover validation report | Within 48 hours of launch | Confirmation that redirects, sitemaps and indexing directives behaved as specified in production |
| Post-launch stability reports | Day 30, 45 and 90 | Performance against the frozen benchmark, separating expected fluctuation from anything structural |
Immediate next steps