diff --git a/documentation/needs-eyes/README.md b/documentation/needs-eyes/README.md
new file mode 100644
index 000000000..52bfd54d9
--- /dev/null
+++ b/documentation/needs-eyes/README.md
@@ -0,0 +1,60 @@
+# needs-eyes — partner-embed fixtures
+
+Under the Playwright policy (Driver, 2026-09-25) only **rega** runs a browser on the VPS, and the
+Driver's laptop is the other pair of eyes. So a check that can only be seen has to be *openable by
+someone else* — not a construct that lives inside one agent's gate process.
+
+These pages are generated, not hand-written:
+
+```
+node internal/check-embedded-rtl.mjs --emit
+```
+
+`check-embedded-rtl` builds its partner page on two ephemeral ports inside its own process. That is
+fine for a headless assertion and useless for a human: "open a partner page at a foreign origin"
+was not a thing anyone but the gate could do. `--emit` writes the same page to disk so the
+needs-eyes item is reproducible.
+
+## What each file is for
+
+| file | channel under test | open it as |
+|---|---|---|
+| `partner-poster-wall.html` | `profile-config.locale` — the channel a **host** sets | plain |
+| `partner-upg-100-mfe.html` | same, on the composite | plain |
+| `partner-poster-wall-lang-ar.html` | `?lang=` — the channel a **reader** follows | **with `?lang=ar`** |
+
+⚠ **The `?lang=ar` file deliberately carries no `locale` in its `profile-config`** (1100 bytes vs
+1114). The two channels reach the document-direction code by different routes, and
+`detectLocale()` reads the URL *first*. If the config also supplied the locale, a reader could
+believe the URL had done it when it had not — and the defect this fixture exists for only fires on
+the URL channel. An earlier version of the emit produced all three files byte-identical, which
+would have handed a reviewer three pages they could not tell apart.
+
+## How to use it
+
+Two terminals, and **the origins must differ** — same-origin hides the bug:
+
+```
+# 1) the tree, WITH CORS (a partner embed uses crossorigin="anonymous", so the
+# browser demands Access-Control-Allow-Origin; `bun run serve` does not send it,
+# a real CDN does)
+npx http-server public -p 47395 --cors -s
+
+# 2) these fixtures
+npx http-server documentation/needs-eyes -p 47393 -s
+
+# 3) open
+http://127.0.0.1:47393/partner-poster-wall-lang-ar.html?lang=ar
+```
+
+## What to look at
+
+The partner page's own heading — **"Partner page"** — must stay **left**-aligned and the
+document's `` must carry no `dir`, while the plugin below it mirrors right-to-left.
+
+If the heading jumps to the right, the embedded plugin flipped its host's whole page and the check
+has **failed**. That was the real defect: an RTL locale was written to
+`document.documentElement.dir` whenever it resolved, so a reader following a `?lang=ar` link to a
+partner's site got the partner's headings, nav and footer flipped. The fix
+(`window.MAP_OWNS_PAGE`, packet/vertical 2a502dd8) is that only a page the generator wrote may
+have its direction set; absence of the flag means restraint.
diff --git a/documentation/needs-eyes/partner-poster-wall-lang-ar.html b/documentation/needs-eyes/partner-poster-wall-lang-ar.html
new file mode 100644
index 000000000..a2373b6ca
--- /dev/null
+++ b/documentation/needs-eyes/partner-poster-wall-lang-ar.html
@@ -0,0 +1,17 @@
+
+
partner
+
+Partner page
+
+
+
+
\ No newline at end of file
diff --git a/documentation/needs-eyes/partner-poster-wall.html b/documentation/needs-eyes/partner-poster-wall.html
new file mode 100644
index 000000000..4278fc0e9
--- /dev/null
+++ b/documentation/needs-eyes/partner-poster-wall.html
@@ -0,0 +1,17 @@
+
+partner
+
+Partner page
+
+
+
+
\ No newline at end of file
diff --git a/documentation/needs-eyes/partner-upg-100-mfe.html b/documentation/needs-eyes/partner-upg-100-mfe.html
new file mode 100644
index 000000000..cc9366c42
--- /dev/null
+++ b/documentation/needs-eyes/partner-upg-100-mfe.html
@@ -0,0 +1,17 @@
+
+partner
+
+Partner page
+
+
+
+
\ No newline at end of file
diff --git a/internal/check-embedded-rtl.mjs b/internal/check-embedded-rtl.mjs
index 4a3ca56a0..6a3215207 100644
--- a/internal/check-embedded-rtl.mjs
+++ b/internal/check-embedded-rtl.mjs
@@ -28,8 +28,21 @@ import { servesThisTree } from './_serves-this-tree.mjs'
import { TREE_NAME } from './_tree-name.mjs'
const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..')
-const BASE = process.argv[2] || process.env.BASE_URL || 'http://127.0.0.1:4173'
+// ⚠ FILTER FLAGS OUT OF THE POSITIONAL. `--emit` was consumed as the baseUrl and the gate
+// reported "SKIP — nothing served at --emit". Exactly the bug I hit on check-leaf-english-leaks
+// last week; the same shape, in a different file, three days apart.
+const BASE = process.argv.slice(2).find((a) => !a.startsWith('--'))
+ || process.env.BASE_URL || 'http://127.0.0.1:4173'
const HOST_PORT = Number(process.env.RTL_HOST_PORT || 47393)
+// ★ --emit WRITES THE PARTNER PAGE TO DISK INSTEAD OF MEASURING IT.
+// Under the Playwright policy (Driver, 2026-09-25) only rega runs a browser, so this check's
+// result now has to be produced by someone else's eyes. But the partner page only ever existed
+// INSIDE this process — two createServer calls on ephemeral ports — so "open a partner page at a
+// foreign origin" was not a thing anyone could actually do. NEEDS-EYES rows 3, 4 and 6 name a
+// runnable probe or an exact URL; row 7 (mine) named a construct that lived in my own memory.
+// --emit closes that: it writes a self-contained page plus a two-line serve recipe, so the item
+// is reproducible by whoever has the browser.
+const EMIT = process.argv.includes('--emit')
let reachable = false
try { const r = await fetch(`${BASE}/${TREE_NAME}/manifest.json`, { signal: AbortSignal.timeout(4000) }); reachable = r.ok } catch { /* precondition */ }
@@ -38,12 +51,23 @@ const treeCheck = await servesThisTree(BASE, ROOT)
if (!treeCheck.ok) { console.error(`EMBEDDED-RTL: NOT MEASURED — ${treeCheck.why}`); process.exit(2) }
// A PARTNER PAGE on a foreign origin: its own is LTR and must stay that way.
+// ⚠ BOTH CHANNELS. profile-config is how a HOST sets the language; ?lang= on the partner's OWN
+// url is how a READER does, and detectLocale() reads the URL FIRST. They reach the
+// document-direction code by different routes, so a check that drives only one proves nothing
+// about the other — which is why the URL case exists as a row here rather than as a variant of
+// the config one. The emit writes a fixture per row, so this array IS the needs-eyes inventory.
const CASES = [
{ id: 'my-upg-100-list', tag: 'my-upg-100-list-map', profile: 'upg-100-mfe' },
{ id: 'my-upg-100-list', tag: 'my-upg-100-list-map', profile: 'poster-wall' },
+ { id: 'my-upg-100-list', tag: 'my-upg-100-list-map', profile: 'poster-wall', urlLang: 'ar' },
]
const TREE_PORT = Number(process.env.RTL_TREE_PORT || 47395)
const TREE = `http://127.0.0.1:${TREE_PORT}`
+// ⚠ THE URL CASE MUST NOT ALSO SET locale IN profile-config. The two channels reach the
+// document-dir code by different routes and the whole point of the ?lang= case is to exercise the
+// URL one alone. Emitting all three files byte-identical (measured: 1114 bytes each) would hand a
+// reader a page that cannot distinguish them — and would let the config channel supply the locale
+// while the reader believed the URL had.
const hostHtml = (c) => `
partner
@@ -56,7 +80,7 @@ const hostHtml = (c) => `