CurrencyTransfer.com · Navigation 2026 · stage 2 · owner review

Navigation 2026 PRD Review Pack

Read this page in ten minutes. It tells you what we build, what you must decide, and what a person must do by hand.

25 September 2026PRD: docs/nav-audit-2026-09-22/prd-nav-2026.md (revision 10)Written in Simplified Technical English
CODEX gpt-6-astra builds it OPUS claude-opus builds it (editor-facing work) HUMAN a person does it LATER after the production switch

Status in one line. The PRD is at revision 10 after ten review rounds. Your seven decisions of 25 September are now requirements with tests. The ten findings left open after round 9 are fixed. The round-10 check reports 0 blockers, 16 major, 0 minor. Eight of the sixteen are repeated split requests. No blocker remains, so conversion can start. See section 8 before you decide.

What "go" means. If you say go, we convert the PRD, which turns it into otto's task list. otto builds the twenty-three stories on a feature branch. Nothing reaches production until the release checklist in section 6 is complete. If you say no-go, nothing changes; stage 1 stays live.

1. What we build

We replace the fixed header menu with one menu that editors manage in WordPress. Stage 1 already shows the agreed design as fixed HTML files, which we call the bundle. Stage 2 renders the same HTML from one WordPress menu, item by item. A script, the parity check, compares the two outputs link by link, so Google sees no change. When the missing pages exist, editors un-hide menu items and the full design appears.

2. The three stages

STAGE 1 · LIVE

Fixed launch menu

In production since 24 September 2026. Tag nav-2026-stage1-v1.1, accessibility hardened. Live links only.

STAGE 2 · THIS PRD

WordPress-managed menu

The same design, rendered from one editable menu. Same links, same order, same landmarks as stage 1.

STAGE 3 · FROZEN

Full four-column design

Frozen at ct-nav-full-design-2avs-yn35.pages.dev, tag nav-2026-full-design-v1. Editors reach it by un-hiding items.

3. What an editor can and cannot do

An editor can

  • Add, remove, rename and reorder any link on Appearance > Menus.
  • Set what an item is: link, group, overview row, featured card, plaque, more-link, button.
  • Hide an item until its page is live. Hidden items do not exist in the page HTML.
  • Give a link a short description, a "New" tag, or a currency badge.
  • Pick a tile icon or a card image from the media library.
  • Point a tile icon at an https image URL instead, for example a file on S3. Such icons keep their own colours on hover.
  • Set a different position for a group on phones only.
  • Give the phone sheet a shorter overview line.
  • Apply the full design with one button, once the pages exist.

An editor cannot

  • Change colours, spacing, fonts or breakpoints. Those live in the stylesheet.
  • Show a link on desktop but not on phones, or the reverse. Google reads the phone menu.
  • Write HTML into the menu.
  • Add a fourth top-level tab. The header holds three.
  • Switch the new menu on or off. That is the operator's job.
  • Upload SVG icons until the Safe SVG plugin is installed (decision 1).

4. The stories

Twenty-three stories. One commit each. otto, the build tool, runs them one at a time. The "depends on" column is the run order, not a plan for parallel work. A person does NAV-001 and the release steps. NAV-018, NAV-020 and NAV-023 run after the production switch, in a second conversion. The operator is the person who runs the release, Stevan or Phil.

IDTitleExecutorDepends onDone when
NAV-001Human prerequisites.user.ini record, Safe SVG install, hub row id (done)HUMANnoneThe release checklist file records each item with evidence.
NAV-002Admin prerequisites and the test runnercore edit walker, Description box, input-limit warning, PHP 7.2/8.3 lintCODEXnoneThe Menus screen shows the Description box and the lint exits 0.
NAV-003Tree builder and flush primitiveroles, hidden pruning, badges, mobile orderCODEXNAV-00273 items in, 52 visible out; tests pass on three PHP runtimes.
NAV-004Item markup, icons, SVG sanitiserattachment icons and https URL iconsCODEXNAV-003, NAV-014All 15 icons pass the sanitiser; tile markup equals the bundle. A URL icon renders as an image with no server fetch.
NAV-005Per-item fields with guarded saveincluding the new Icon URL fieldOPUSNAV-003Each field round-trips, the Icon URL included; a save without the form marker writes nothing.
NAV-006Media picker for icons and imagesOPUSNAV-005, NAV-010, NAV-017An editor picks an icon, saves once, and the tile shows it.
NAV-007Wide panel markup (1200 px and up)CODEXNAV-004, NAV-014The parity check and a byte comparison against the bundle both pass for every tab.
NAV-008Medium panel markup (600 to 1199 px)CODEXNAV-004, NAV-007, NAV-014The same two checks pass against the bundle's medium blocks.
NAV-009Phone sheet markup (below 600 px)CODEXNAV-004, NAV-014The same two checks pass against the sheet; mobile order works.
NAV-010Render integration on stage 1fragment filter, composition, preview parametersCODEXNAV-007, 008, 009, 014, 016, 017Switch off: header identical to stage 1. Menu active: the parity check passes.
NAV-011Cache lifecycleone cached row, gated invalidation, preview bypassCODEXNAV-010A flush deletes the cached menu HTML. After a flush the first load rebuilds it and the second reuses it. Unrelated edits leave it in place.
NAV-012Section map for the body classCODEXNAV-011, NAV-022Eighteen URLs carry the expected section class. A blog post carries none.
NAV-013Cloudflare edge purge on every changeCODEXNAV-011One purge per request that flushed; a label change shows on production within 60 seconds.
NAV-014Harness and baselinesfixtures, checker copy, states port, visual and Lighthouse toolsCODEXNAV-002All fixtures committed; the baseline runs are quoted.
NAV-015Verification of the rendered menuscreenshots, link states, behaviour, LighthouseCODEXNAV-011, 012, 014, 017, 021Screenshots within 1 % of stage 1; 33 link-colour probes pass; Google Lighthouse speed scores stay within tolerance.
NAV-016Seed the menu from Tools; activate and deactivateOPUSNAV-003, NAV-014Seed creates 73 items, 21 hidden; Activate and Deactivate set and clear the option.
NAV-017Icon import, full-design and launch presetsOPUSNAV-016, NAV-00415 icons imported once; the preset un-hides only targets that exist.
NAV-018Second critical-CSS set LATERCODEXNAV-019Seven pruned files hold no legacy menu selectors; first paint unchanged.
NAV-019Launch gate and release checklistCODEXNAV-006, 013, 015, 017, 021, 022The gate script reports zero failures on local and staging, one blog post included; the release checklist is written.
NAV-020Legacy removal and menu export LATEROPUSNAV-019, NAV-018Legacy render path and CSS gone; three legacy menus exported, none deleted by code.
NAV-021Full-design stylesheet, printed only when neededCODEXNAV-010, 014, 017Nothing prints in launch mode; full-design regions within 1 % of the archive.
NAV-022Blog posts and category pages: new header and sheetblog category links kept below the barCODEXNAV-010, NAV-014A post and a category page pass the same parity check as the homepage. The blog category row keeps its styling. Switch off: the old blog header is byte-identical.
NAV-023Cleanup verified on staging LATERthe committed cleanup deployed by sha, retire action, gate, rollback rehearsalCODEXNAV-020Staging runs the deployed cleanup revision. The gate reports zero failures. The rollback rehearsal passes.

5. Decisions taken

You took these decisions on 25 September 2026. The PRD records each one as a requirement with a test.

  1. 1. SVG icons: Safe SVG plugin approved, plus URL icons. A person installs Safe SVG on staging and production. Editors can also point a tile icon at an https image URL, for example a file on S3. The URL wins over a chosen file. The page shows it as a small image and never fetches it on the server. Such icons keep their own colours on hover. Decided: (a), with the URL option.
  2. 2. The "All industries" link. The hub page row now carries the id industries on local, staging and production. The menu links to /business-foreign-exchange#industries. No exception is needed. Done.
  3. 3. Two pages lose their sitewide header link. In launch mode /product and payplexo.com are not in the menu. Accepted.
  4. 4. One menu, not two. Desktop and phone render from one menu. Phones get their own group order through a "Position on mobile" field. Confirmed.
  5. 5. Blog posts and blog category pages get the new header in stage 2. New story NAV-022 covers single posts and the four blog category pages. On production, only /blog shows the new header today. Posts and the four category pages still show the legacy blog header. We checked production on 25 September. NAV-022 gives all of them the new header and the phone sheet. The blog category links stay below the bar and keep their styling. These pages carry no section class, because no tab leads to the blog. Decided: stage 2.
  6. 6. No permanent underline on the current desktop tab. Only the open tab is underlined. Declined.

The two Convert experiments are out of scope. You handle them outside this project. They are no longer a release step.

6. Manual steps

Done

  • .user.ini sets max_input_vars=3000 on production and staging. Verified 24 September 2026.
  • WP-CLI runs on production at /home/phil/bin/wp.
  • Stage 1 is live on production behind the ctw_nav_v2 switch.
  • The hub page row has the id industries on local, staging and production. Done 25 September 2026.

To do

  1. Install Safe SVG on staging and production (decision 1).
  2. Open Tools > Seed navigation 2026 on each environment. Click Seed, then Import icons. Order: local, staging, production.
  3. Merge the build branch into main, tag it, and deploy. Check that production reports that revision.
  4. The menu is not yet active after the deploy. The site keeps showing the stage-1 HTML.
  5. Click Activate menu on the Tools page. This is stage 2's own switch. Stage 1's switch stays as the whole-menu rollback.
  6. Purge Cloudflare after each command-line change: ./deploy purge prod.
  7. Rollback at any time: click Deactivate menu, then purge. No deploy is needed.
  8. Seven days after activation: convert and run NAV-018, NAV-020 and NAV-023.

7. Risks

RiskMitigation
The rendered menu drifts from the bundle, so Google sees different links.Every markup story must pass the parity check against the bundle, link by link.
Editors' changes stay invisible for hours because Cloudflare caches whole pages.Every menu change deletes the cached HTML and sends one Cloudflare purge; a production probe proves it.
Unrelated edits, such as autosaves, purge the whole edge cache many times a day.Only changes to the menu, its pages or its icons trigger a purge; unit tests cover the rest.
Code that runs on PHP 7.4 locally fails on PHP 7.2 in production.Every PHP story runs its tests inside PHP 7.2 and PHP 8.3 containers.
A link to a private, missing or redirecting page ships in the menu.Unpublished targets never render, and the launch gate probes every URL on each environment.
The new header breaks the blog post layout.The switch-off state keeps the old blog header byte for byte. Probes and screenshots cover one post and one category page.

8. Review history

Ten rounds ran. The checker, otto check, is an adversarial reviewer that reads the PRD as a builder would. FIX-FIRST means it wants changes before the build starts.

RoundResultMain change
1 · otto check1 blocker, 35 major, 1 minor. FIX-FIRST.Real frames cited; tooling moved into the theme repo; the old save handler unhooked.
SEO auditStage 2 "pass with fixes".Tabs stay links; hidden items leave the HTML; the parity check becomes the acceptance test.
2 · otto check2 blockers, 37 major. FIX-FIRST.The PRD now builds on the stage-1 code with one filter line.
3 · otto check1 blocker, 32 major. FIX-FIRST.Symbol anchors; a new story for the full-design styles.
4 · otto check1 blocker, 31 major, 1 minor. FIX-FIRST.One base URL; a phone subline field; safer cache writes.
5 · independent panel92 findings: 13 blocker, 42 major, 37 minor. 49 stood after refutation.Extra editor fields so one menu reproduces the bundle; a race-free cache design.
6 · otto check0 blockers, 28 major, 2 minor. FIX-FIRST.Random cache tokens; a stable section key per tab.
7 · otto check0 blockers, 23 major, 2 minor. FIX-FIRST.Fifteen new findings fixed in revision 8, see below.
8 · otto check0 blockers, 21 major, 0 minor. FIX-FIRST.Eight are repeated split requests, declined. Thirteen new findings, fixed in revision 9.
9 · otto check3 blockers, 18 major, 0 minor. FIX-FIRST. The three blockers were fixed in revision 9.1.Owner decisions folded in; thirteen round-8 findings fixed; new story NAV-022.
10 · otto check (final)0 blockers, 16 major, 0 minor. FIX-FIRST. No blocker: conversion can start.Ten round-9 findings fixed in revision 10; new story NAV-023. Eight of the sixteen are repeated split requests.

What revision 8 changed

Fifteen findings from round 7, all fixed. The largest: a helper function was called before its story defined it. A WordPress catch-all rule made every path look valid, so missing pages could slip through. A custom link pointed the section map at the wrong id. A plaque without its card had no desktop position. The cache could store stale content during a cold start. The purge could run before the final cache reset.

What revision 9 changed

Your seven decisions became requirements with tests. Icons gained an https URL option. The "All industries" link points at the hub row. Blog posts and category pages get the new header in a new story, NAV-022. The thirteen findings from round 8 are fixed. The largest: the cache dependency record is written before pages are read, so a late edit cannot be missed. A tab without an overview keeps its link on phones. The release checklist now merges the build into main and checks the deployed revision.

What revision 10 changed

The ten findings from round 9, all fixed. The cache now trusts its dependency record only while the record matches the current cache token. Page status is read fresh from the database, not from a cache. A blog post placed in the menu invalidates the cache like a page. The blog category row keeps its styling under its new id. The archive comparison corrects for the September colour fix before it compares layout. The release steps keep evidence outside the code checkout, because the deploy tool refuses a dirty checkout. The cleanup story is verified locally; a new story, NAV-023, verifies the deployed cleanup on staging.

What is still open after round 10

Eight new major findings from round 10 remain open. None is a blocker. They concern cache edge cases, taxonomy menu items, and two checklist details. We treat them as inputs to the conversion step, not as reasons to wait. Eight more findings are repeated split requests, declined.

Declined every round since round 2: splitting eight large stories. The task sizer splits stories at conversion time, and each story is one file or one tool set.

9. Links

Prepared 25 September 2026 from docs/nav-audit-2026-09-22/prd-nav-2026.md, revision 10. Unlisted page: do not index.