From 76fedaaf119ef91c89904b49f6b436a709276af9 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Mon, 10 Aug 2026 13:48:08 -0700 Subject: [PATCH] =?UTF-8?q?Drop=20all=20nine=20zone-shell=20audit=20exempt?= =?UTF-8?q?ions=20=E2=80=94=20every=20child=20now=20renders=20the=20shell?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All nine bare legacy zone children shipped the PolicyEngine site shell (header/nav + footer, rendered by the child app) and deployed: /uk/scotland-income-tax-reform scotland-income-tax-reform#11 /uk/student-loan-visualisation student-loan-visualisation#4 /us/obbba-household-explorer obbba-household-by-household#245 /uk/uc-rebalancing uc-rebalancing#4 /uk/cancelling-fuel-duty-rise cancelling-fuel-duty-rise#6 /uk/young-worker-nics young-worker-nics#5 /uk/nics-exemption-inactive-employees nics-exemption-inactive-employees#11 /uk/electricity-vat-cut electricity-vat-cut#1 /uk/bus-fare-cap bus-fare-cap#9 SHELL_BRAND_EXEMPT_SOURCES is now empty and the tests pin it there. Full production audit passes with zero exemptions: 67/67 enforced app-zone routes render the shell. Co-Authored-By: Claude Fable 5 --- .github/scripts/audit-app-zone-shell.mjs | 37 ++++++------------- .github/scripts/audit-app-zone-shell.test.mjs | 31 +++++++--------- CLAUDE.md | 2 +- changelog_entry.yaml | 1 + 4 files changed, 26 insertions(+), 45 deletions(-) diff --git a/.github/scripts/audit-app-zone-shell.mjs b/.github/scripts/audit-app-zone-shell.mjs index 65d767a0b..e752af2ae 100644 --- a/.github/scripts/audit-app-zone-shell.mjs +++ b/.github/scripts/audit-app-zone-shell.mjs @@ -36,32 +36,17 @@ export const REQUIRED_NAV_LABELS = ["Research", "Model", "API", "Donate"]; const TOP_SHELL_SELECTOR = 'header, nav, [data-testid*="header" i], [data-testid*="site-header" i], a, button, img, [aria-label]'; -// Routes intentionally served WITHOUT a child-rendered PolicyEngine header. -// These tools are embedded under policyengine.org, which already provides the -// site header/nav, so the maintainers chose not to duplicate the PolicyEngine -// shell inside the child app. These routes are still audited for liveness -// (HTTP status, runtime errors, blank pages) — only the top-shell brand/nav -// assertion is skipped. Remove an entry to re-enforce the full shell on it. -// /uk/scotland-income-tax-reform — PolicyEngine/scotland-income-tax-reform#8 -// /uk/student-loan-visualisation — PolicyEngine/student-loan-visualisation#3 -// /us/obbba-household-explorer — PolicyEngine/obbba-household-by-household#240 -// /uk/uc-rebalancing — PolicyEngine/uc-rebalancing -// /uk/cancelling-fuel-duty-rise — PolicyEngine/cancelling-fuel-duty-rise -// /uk/young-worker-nics — PolicyEngine/young-worker-nics -// /uk/nics-exemption-inactive-employees — PolicyEngine/nics-exemption-inactive-employees -// /uk/electricity-vat-cut — PolicyEngine/electricity-vat-cut -// /uk/bus-fare-cap — PolicyEngine/bus-fare-cap -export const SHELL_BRAND_EXEMPT_SOURCES = [ - "/uk/scotland-income-tax-reform", - "/uk/student-loan-visualisation", - "/us/obbba-household-explorer", - "/uk/uc-rebalancing", - "/uk/cancelling-fuel-duty-rise", - "/uk/young-worker-nics", - "/uk/nics-exemption-inactive-employees", - "/uk/electricity-vat-cut", - "/uk/bus-fare-cap", -]; +// Routes temporarily served WITHOUT a child-rendered PolicyEngine header. +// Empty and it stays that way: every zone child now renders the site shell +// itself (the multizone rewrite does not inject the parent shell), and the +// zone-shell test asserts this list only ever shrinks. The last nine legacy +// entries were removed after each repo shipped its shell — see +// scotland-income-tax-reform#11, student-loan-visualisation#4, +// obbba-household-by-household#245, uc-rebalancing#4, +// cancelling-fuel-duty-rise#6, young-worker-nics#5, +// nics-exemption-inactive-employees#11, electricity-vat-cut#1, and +// bus-fare-cap#9. +export const SHELL_BRAND_EXEMPT_SOURCES = []; export function isShellBrandExempt(source) { return SHELL_BRAND_EXEMPT_SOURCES.some( diff --git a/.github/scripts/audit-app-zone-shell.test.mjs b/.github/scripts/audit-app-zone-shell.test.mjs index b7c58d103..2546658a3 100644 --- a/.github/scripts/audit-app-zone-shell.test.mjs +++ b/.github/scripts/audit-app-zone-shell.test.mjs @@ -7,6 +7,7 @@ import { inspectTopShellData, isShellBrandExempt, resolveDestinationForSource, + SHELL_BRAND_EXEMPT_SOURCES, shouldAllowDestinationFallback, sourcePathFromSitemapLoc, } from "./audit-app-zone-shell.mjs"; @@ -250,31 +251,25 @@ describe("shouldAllowDestinationFallback", () => { }); describe("isShellBrandExempt", () => { - test("exempts configured routes and their subpaths", () => { - assert.equal(isShellBrandExempt("/uk/scotland-income-tax-reform"), true); + test("exempts nothing — every zone child renders its own shell", () => { + // The list only ever shrinks; it drained to empty when the last nine + // legacy children shipped their shells. Keep it empty: new zone embeds + // must render the site shell from day one. + assert.equal(SHELL_BRAND_EXEMPT_SOURCES.length, 0); + }); + + test("enforces the shell on formerly exempt and never-exempt routes alike", () => { + assert.equal(isShellBrandExempt("/uk/scotland-income-tax-reform"), false); assert.equal( isShellBrandExempt("/uk/student-loan-visualisation/budget-impact"), - true, - ); - assert.equal(isShellBrandExempt("/uk/uc-rebalancing"), true); - assert.equal(isShellBrandExempt("/us/obbba-household-explorer"), true); - assert.equal(isShellBrandExempt("/uk/young-worker-nics"), true); - assert.equal( - isShellBrandExempt("/uk/nics-exemption-inactive-employees"), - true, + false, ); - assert.equal(isShellBrandExempt("/uk/electricity-vat-cut"), true); - assert.equal(isShellBrandExempt("/uk/bus-fare-cap"), true); - }); - - test("does not exempt shelled children, other routes, or partial-name collisions", () => { - // snap-qc-sim renders the full site shell (PolicyEngine/snap-qc-sim#26), - // so its route left the exemption list and the audit enforces it. + assert.equal(isShellBrandExempt("/us/obbba-household-explorer"), false); + assert.equal(isShellBrandExempt("/uk/bus-fare-cap"), false); assert.equal( isShellBrandExempt("/us/snap-payment-error-simulator"), false, ); assert.equal(isShellBrandExempt("/uk/marriage"), false); - assert.equal(isShellBrandExempt("/uk/uc-rebalancing-extended"), false); }); }); diff --git a/CLAUDE.md b/CLAUDE.md index 7a3408b87..bd18edeaf 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -106,7 +106,7 @@ const PolicyEngineLogo = "/assets/logos/policyengine/white.svg"; ### The shell rule -**Everything served on policyengine.org carries the PolicyEngine site shell — header/nav and footer — and zone children must render it themselves** (the aca-calc / snap-qc-sim pattern: global nav with the wordmark, Research, Model, API, Donate, plus the site footer links). There is no shelled fallthrough for zone paths: the website proxies each tool's path straight to the child, and `AppPage`/apps.json alone has **no production route** (removing a zone rewrite 404s the path — see #1143/#1144). The `app-zone-shell-audit` enforces the header on zone routes; `SHELL_BRAND_EXEMPT_SOURCES` lists the remaining bare legacy children and should only ever shrink — remove a tool's entry in the same change that ships its shell. +**Everything served on policyengine.org carries the PolicyEngine site shell — header/nav and footer — and zone children must render it themselves** (the aca-calc / snap-qc-sim pattern: global nav with the wordmark, Research, Model, API, Donate, plus the site footer links). There is no shelled fallthrough for zone paths: the website proxies each tool's path straight to the child, and `AppPage`/apps.json alone has **no production route** (removing a zone rewrite 404s the path — see #1143/#1144). The `app-zone-shell-audit` enforces the header on zone routes; `SHELL_BRAND_EXEMPT_SOURCES` is empty and stays that way — the last nine bare legacy children shipped their shells in August 2026, and new zone embeds must render the shell from day one. ### Next.js multizones (default for all new tools) diff --git a/changelog_entry.yaml b/changelog_entry.yaml index 2cb47705e..b2b04d848 100644 --- a/changelog_entry.yaml +++ b/changelog_entry.yaml @@ -1,2 +1,3 @@ - Enforce the site shell on the SNAP payment error simulator route and fix four stale app iframe sources +- Enforce the site shell on the last nine bare embedded tools, emptying the zone-shell audit exemption list - Redirect /uk/cec (the retired Citizens' Economic Council simulator, embedded by citizensecon.org.uk) to /uk instead of a 404