aboutsummaryrefslogtreecommitdiffstats
path: root/packages
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-09-20 01:52:01 +0200
committerChristophe Besson <cbesson@gmail.com>2026-09-20 01:52:01 +0200
commit66abba3d08021b1ff538d6266e4b4e590407bde2 (patch)
tree891999648a9654c84e0590b36e0bc95f17d84c98 /packages
parent6770ed9cd36fe68610b74826520f8c6effc121f6 (diff)
downloadmeshbay-66abba3d08021b1ff538d6266e4b4e590407bde2.tar.gz
feat(hub): show the node's public key in Node → Overview
It was only the Node ID row's fallback, so it vanished the moment the node announced itself — and was labelled Node ID when it did show. Own row, copy button, and the profile's instructions no longer name the node dashboard removed on 2026-09-01. `.node-key` wraps: 44 base64 characters with no break opportunity pushed a 412px document to 417px, which unpins every sticky element on the page. The width probe now measures the Overview table with a real key in it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Diffstat (limited to 'packages')
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/de.js7
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/en.js5
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/es.js8
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js8
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/it.js8
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js6
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js8
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js8
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/pt-BR.js8
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js7
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/node-page.js22
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/style.css6
-rw-r--r--packages/meshbay-hub/tests/test_node_page_width_measured.py54
13 files changed, 138 insertions, 17 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/de.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/de.js
index aea1196..47f0b31 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/de.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/de.js
@@ -500,7 +500,9 @@ export default {
'settings.node_key': 'Node verknüpfen',
'settings.node_key_desc': 'Wenn Sie einen MeshBay-Node betreiben, fügen Sie hier '
+ 'dessen öffentlichen Ed25519-Schlüssel ein, um ihn mit Ihrem Konto zu '
- + 'verknüpfen. Sie finden diesen Schlüssel im Administrations-Dashboard Ihres Nodes.',
+ + 'verknüpfen. Führen Sie `meshbay-node status` auf dem Rechner des Nodes aus, um '
+ + 'den Schlüssel zu lesen, oder kopieren Sie ihn im Desktop-Client unter '
+ + 'Node → Overview.',
'settings.node_key_placeholder': 'Öffentlichen Ed25519-Schlüssel des Nodes einfügen (base64)',
'settings.node_key_submit': 'Node verknüpfen',
'settings.node_key_success': 'Node erfolgreich verknüpft',
@@ -1087,6 +1089,9 @@ export default {
'node.overview': 'Overview',
'node.overview_version': 'Version',
'node.overview_node_id': 'Node ID',
+ 'node.overview_node_key': 'Node-Schlüssel',
+ 'node.overview_node_key_copy': 'Kopieren',
+ 'node.overview_node_key_copied': 'Kopiert',
'node.overview_quic_port': 'QUIC port',
'node.overview_hub': 'Hub',
'node.node_roster': 'Node roster',
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/en.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/en.js
index d9172a6..92a45dd 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/en.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/en.js
@@ -490,7 +490,7 @@ export default {
'settings.groups': 'Group notifications',
'settings.notifications': 'Notifications',
'settings.node_key': 'Link Node',
- 'settings.node_key_desc': 'If you operate a MeshBay node, paste its Ed25519 public key here to link it to your account. You can find this key in your node\'s admin dashboard.',
+ 'settings.node_key_desc': 'If you operate a MeshBay node, paste its Ed25519 public key here to link it to your account. Run `meshbay-node status` on the machine running the node to read the key, or copy it from Node \u2192 Overview in the desktop client.',
'settings.node_key_placeholder': 'Paste node Ed25519 public key (base64)',
'settings.node_key_submit': 'Link Node',
'settings.node_key_success': 'Node linked successfully',
@@ -1073,6 +1073,9 @@ export default {
'node.overview': 'Overview',
'node.overview_version': 'Version',
'node.overview_node_id': 'Node ID',
+ 'node.overview_node_key': 'Node key',
+ 'node.overview_node_key_copy': 'Copy',
+ 'node.overview_node_key_copied': 'Copied',
'node.overview_quic_port': 'QUIC port',
'node.overview_hub': 'Hub',
'node.node_roster': 'Node roster',
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/es.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/es.js
index fc0e639..ae2a405 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/es.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/es.js
@@ -495,8 +495,9 @@ export default {
'settings.notifications': 'Notificaciones',
'settings.node_key': 'Vincular un node',
'settings.node_key_desc': 'Si administra un node MeshBay, pegue aquí su clave '
- + 'pública Ed25519 para vincularlo a su cuenta. Encontrará esa clave en el panel '
- + 'de administración de su node.',
+ + 'pública Ed25519 para vincularlo a su cuenta. Ejecute `meshbay-node status` en '
+ + 'la máquina que aloja el node para leer la clave, o cópiela desde '
+ + 'Node → Overview en el cliente de escritorio.',
'settings.node_key_placeholder': 'Pegue la clave pública Ed25519 del node (base64)',
'settings.node_key_submit': 'Vincular el node',
'settings.node_key_success': 'Node vinculado correctamente',
@@ -1082,6 +1083,9 @@ export default {
'node.overview': 'Overview',
'node.overview_version': 'Version',
'node.overview_node_id': 'Node ID',
+ 'node.overview_node_key': 'Clave del node',
+ 'node.overview_node_key_copy': 'Copiar',
+ 'node.overview_node_key_copied': 'Copiada',
'node.overview_quic_port': 'QUIC port',
'node.overview_hub': 'Hub',
'node.node_roster': 'Node roster',
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js
index 5eb8d60..795a06c 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js
@@ -498,8 +498,9 @@ export default {
'settings.notifications': 'Notifications',
'settings.node_key': 'Associer un node',
'settings.node_key_desc': 'Si vous exploitez un node MeshBay, collez ici sa clé '
- + 'publique Ed25519 pour l’associer à votre compte. Vous trouverez cette clé '
- + 'dans le tableau de bord d’administration de votre node.',
+ + 'publique Ed25519 pour l’associer à votre compte. Lancez `meshbay-node status` '
+ + 'sur la machine qui héberge le node pour lire cette clé, ou copiez-la depuis '
+ + 'Node → Overview dans le client de bureau.',
'settings.node_key_placeholder': 'Collez la clé publique Ed25519 du node (base64)',
'settings.node_key_submit': 'Associer le node',
'settings.node_key_success': 'Node associé avec succès',
@@ -1100,6 +1101,9 @@ export default {
'node.overview': 'Overview',
'node.overview_version': 'Version',
'node.overview_node_id': 'Node ID',
+ 'node.overview_node_key': 'Clé du node',
+ 'node.overview_node_key_copy': 'Copier',
+ 'node.overview_node_key_copied': 'Copiée',
'node.overview_quic_port': 'QUIC port',
'node.overview_hub': 'Hub',
'node.node_roster': 'Node roster',
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/it.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/it.js
index 6d12cb3..2cb1a31 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/it.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/it.js
@@ -498,8 +498,9 @@ export default {
'settings.notifications': 'Notifiche',
'settings.node_key': 'Collega un node',
'settings.node_key_desc': 'Se gestisce un node MeshBay, incolli qui la sua chiave '
- + 'pubblica Ed25519 per collegarlo al suo account. Trova questa chiave nel '
- + 'pannello di amministrazione del suo node.',
+ + 'pubblica Ed25519 per collegarlo al suo account. Esegua `meshbay-node status` '
+ + 'sulla macchina che ospita il node per leggere la chiave, oppure la copi da '
+ + 'Node → Overview nel client desktop.',
'settings.node_key_placeholder': 'Incolli la chiave pubblica Ed25519 del node (base64)',
'settings.node_key_submit': 'Collega il node',
'settings.node_key_success': 'Node collegato correttamente',
@@ -1096,6 +1097,9 @@ export default {
'node.overview': 'Overview',
'node.overview_version': 'Version',
'node.overview_node_id': 'Node ID',
+ 'node.overview_node_key': 'Chiave del node',
+ 'node.overview_node_key_copy': 'Copia',
+ 'node.overview_node_key_copied': 'Copiata',
'node.overview_quic_port': 'QUIC port',
'node.overview_hub': 'Hub',
'node.node_roster': 'Node roster',
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js
index f4ced88..e26110f 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js
@@ -493,7 +493,8 @@ export default {
'settings.node_key': 'node を連携',
'settings.node_key_desc': 'MeshBay の node を運営している場合は、その Ed25519 '
+ '公開鍵をここに貼り付けて、アカウントに連携してください。'
- + 'この鍵は node の管理ダッシュボードで確認できます。',
+ + 'node を動かしているマシンで `meshbay-node status` を実行するか、'
+ + 'デスクトップクライアントの Node → Overview からコピーできます。',
'settings.node_key_placeholder': 'node の Ed25519 公開鍵を貼り付け(base64)',
'settings.node_key_submit': 'node を連携',
'settings.node_key_success': 'node を連携しました',
@@ -1080,6 +1081,9 @@ export default {
'node.overview': 'Overview',
'node.overview_version': 'Version',
'node.overview_node_id': 'Node ID',
+ 'node.overview_node_key': 'node の鍵',
+ 'node.overview_node_key_copy': 'コピー',
+ 'node.overview_node_key_copied': 'コピーしました',
'node.overview_quic_port': 'QUIC port',
'node.overview_hub': 'Hub',
'node.node_roster': 'Node roster',
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js
index 31a2321..ce3cdf9 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js
@@ -499,8 +499,9 @@ export default {
'settings.notifications': 'Meldingen',
'settings.node_key': 'Node koppelen',
'settings.node_key_desc': 'Als u een MeshBay-node beheert, plak hier dan de '
- + 'openbare Ed25519-sleutel ervan om hem aan uw account te koppelen. U vindt die '
- + 'sleutel in het beheerdersdashboard van uw node.',
+ + 'openbare Ed25519-sleutel ervan om hem aan uw account te koppelen. Voer '
+ + '`meshbay-node status` uit op de machine waarop de node draait om de sleutel te '
+ + 'lezen, of kopieer hem via Node → Overview in de desktopclient.',
'settings.node_key_placeholder': 'Plak de openbare Ed25519-sleutel van de node (base64)',
'settings.node_key_submit': 'Node koppelen',
'settings.node_key_success': 'Node gekoppeld',
@@ -1098,6 +1099,9 @@ export default {
'node.overview': 'Overview',
'node.overview_version': 'Version',
'node.overview_node_id': 'Node ID',
+ 'node.overview_node_key': 'Node-sleutel',
+ 'node.overview_node_key_copy': 'Kopiëren',
+ 'node.overview_node_key_copied': 'Gekopieerd',
'node.overview_quic_port': 'QUIC port',
'node.overview_hub': 'Hub',
'node.node_roster': 'Node roster',
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js
index 463a6a9..7f347da 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js
@@ -511,8 +511,9 @@ export default {
'settings.notifications': 'Powiadomienia',
'settings.node_key': 'Powiąż node',
'settings.node_key_desc': 'Osoby prowadzące własny node MeshBay mogą wkleić tutaj '
- + 'jego klucz publiczny Ed25519, aby powiązać go ze swoim kontem. Klucz ten znajduje '
- + 'się w panelu administracyjnym node.',
+ + 'jego klucz publiczny Ed25519, aby powiązać go ze swoim kontem. Aby odczytać '
+ + 'klucz, uruchom `meshbay-node status` na maszynie z node lub skopiuj go z '
+ + 'Node → Overview w kliencie desktopowym.',
'settings.node_key_placeholder': 'Wklej klucz publiczny Ed25519 node (base64)',
'settings.node_key_submit': 'Powiąż node',
'settings.node_key_success': 'Node został powiązany',
@@ -1124,6 +1125,9 @@ export default {
'node.overview': 'Overview',
'node.overview_version': 'Version',
'node.overview_node_id': 'Node ID',
+ 'node.overview_node_key': 'Klucz node',
+ 'node.overview_node_key_copy': 'Kopiuj',
+ 'node.overview_node_key_copied': 'Skopiowano',
'node.overview_quic_port': 'QUIC port',
'node.overview_hub': 'Hub',
'node.node_roster': 'Node roster',
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/pt-BR.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/pt-BR.js
index 20822ee..f0f1077 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/pt-BR.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/pt-BR.js
@@ -497,8 +497,9 @@ export default {
'settings.notifications': 'Notificações',
'settings.node_key': 'Vincular um node',
'settings.node_key_desc': 'Se você opera um node MeshBay, cole aqui a chave pública '
- + 'Ed25519 dele para vinculá-lo à sua conta. Essa chave está no painel de '
- + 'administração do seu node.',
+ + 'Ed25519 dele para vinculá-lo à sua conta. Execute `meshbay-node status` na '
+ + 'máquina que hospeda o node para ler a chave, ou copie-a em '
+ + 'Node → Overview no cliente desktop.',
'settings.node_key_placeholder': 'Cole a chave pública Ed25519 do node (base64)',
'settings.node_key_submit': 'Vincular o node',
'settings.node_key_success': 'Node vinculado com sucesso',
@@ -1083,6 +1084,9 @@ export default {
'node.overview': 'Overview',
'node.overview_version': 'Version',
'node.overview_node_id': 'Node ID',
+ 'node.overview_node_key': 'Chave do node',
+ 'node.overview_node_key_copy': 'Copiar',
+ 'node.overview_node_key_copied': 'Copiada',
'node.overview_quic_port': 'QUIC port',
'node.overview_hub': 'Hub',
'node.node_roster': 'Node roster',
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js
index b2d7591..be337b7 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js
@@ -486,7 +486,9 @@ export default {
'settings.notifications': '通知',
'settings.node_key': '关联 node',
'settings.node_key_desc': '如果您运营着一个 MeshBay node,请在此粘贴它的 Ed25519 '
- + '公钥,以将其关联到您的账户。该密钥可在您 node 的管理面板中找到。',
+ + '公钥,以将其关联到您的账户。在运行 node 的机器上执行 '
+ + '`meshbay-node status` 可读取该密钥,或在桌面客户端的 '
+ + 'Node → Overview 中复制。',
'settings.node_key_placeholder': '粘贴 node 的 Ed25519 公钥(base64)',
'settings.node_key_submit': '关联 node',
'settings.node_key_success': 'node 关联成功',
@@ -1068,6 +1070,9 @@ export default {
'node.overview': 'Overview',
'node.overview_version': 'Version',
'node.overview_node_id': 'Node ID',
+ 'node.overview_node_key': 'node 密钥',
+ 'node.overview_node_key_copy': '复制',
+ 'node.overview_node_key_copied': '已复制',
'node.overview_quic_port': 'QUIC port',
'node.overview_hub': 'Hub',
'node.node_roster': 'Node roster',
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/node-page.js b/packages/meshbay-hub/src/meshbay_hub/static/node-page.js
index 2edcbab..0b05dad 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/node-page.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/node-page.js
@@ -216,6 +216,7 @@ export function NodePage({ groups, token, username }) {
const [nodeRoster, setNodeRoster] = useState(null);
const [unlinkBusy, setUnlinkBusy] = useState(false);
const [tab, setTab] = useState('overview');
+ const [keyCopied, setKeyCopied] = useState(false);
const fetchStatus = useCallback(async () => {
setStatus('connecting');
@@ -257,6 +258,16 @@ export function NodePage({ groups, token, username }) {
} catch {}
}, []);
+ const copyNodeKey = useCallback(async () => {
+ const pk = nodeInfo && nodeInfo.pk_node_ed25519;
+ if (!pk) return;
+ try {
+ await navigator.clipboard.writeText(pk);
+ setKeyCopied(true);
+ setTimeout(() => setKeyCopied(false), 2000);
+ } catch { /* clipboard blocked -- the key is on screen to copy by hand */ }
+ }, [nodeInfo]);
+
const addRoot = useCallback(async (groupId) => {
const chosen = await platform.rootPicker.choose();
if (!chosen) return;
@@ -725,7 +736,16 @@ export function NodePage({ groups, token, username }) {
<tbody>
<tr><td>${t('node.overview_version')}</td><td>${nodeInfo.version || '—'}</td></tr>
<tr><td>${t('node.overview_node_id')}</td>
- <td><code>${nodeInfo.endpoint_hint || nodeInfo.pk_node_ed25519 || '—'}</code></td></tr>
+ <td><code>${nodeInfo.endpoint_hint || '—'}</code></td></tr>
+ <tr><td>${t('node.overview_node_key')}</td>
+ <td>
+ <code class="node-key">${nodeInfo.pk_node_ed25519 || '—'}</code>
+ ${nodeInfo.pk_node_ed25519 && html`
+ <button class="btn btn-small btn-secondary" onClick=${copyNodeKey}>
+ ${keyCopied ? t('node.overview_node_key_copied')
+ : t('node.overview_node_key_copy')}
+ </button>`}
+ </td></tr>
<tr><td>${t('node.overview_quic_port')}</td><td>${nodeInfo.quic_port || '—'}</td></tr>
<tr><td>${t('node.overview_hub')}</td><td>${nodeInfo.hub_url || '—'}</td></tr>
</tbody>
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/style.css b/packages/meshbay-hub/src/meshbay_hub/static/style.css
index 63f631a..7c36ed7 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/style.css
+++ b/packages/meshbay-hub/src/meshbay_hub/static/style.css
@@ -3349,6 +3349,12 @@ h2 .gn-owner, h3 .gn-owner { font-size: 0.55em; }
overflow-x: auto;
margin-top: 4px;
}
+/* An Ed25519 key is 44 base64 characters with no break opportunity in them. */
+.node-key {
+ word-break: break-all;
+ overflow-wrap: anywhere;
+ margin-right: 8px;
+}
/* Audit rows: keep the fixed-shape columns on one line (the IP must never be
clipped); only the free-text detail column wraps. */
.node-table-audit td,
diff --git a/packages/meshbay-hub/tests/test_node_page_width_measured.py b/packages/meshbay-hub/tests/test_node_page_width_measured.py
index ebf07ab..bd6a231 100644
--- a/packages/meshbay-hub/tests/test_node_page_width_measured.py
+++ b/packages/meshbay-hub/tests/test_node_page_width_measured.py
@@ -41,6 +41,29 @@ AUDIT_ROWS = [
]
+# A real Ed25519 public key as the node reports it: 32 bytes of base64, 44
+# characters with not one break opportunity among them. Shortening it here
+# would measure the fixture instead of the page -- the exact mistake that let
+# a folder name and then a translated column head push this page sideways.
+NODE_KEY = "kP3vQ8mZ2rT7xN1bY6wL4hJ9cF5dS0aG8eR2uI7oK4M="
+
+
+def _overview_table():
+ rows = [
+ ("Version", "0.14.0"),
+ ("Node ID", "203.0.113.7:0"),
+ ("Node key", f'<code class="node-key">{NODE_KEY}</code>'
+ '<button class="btn btn-small btn-secondary">Copy</button>'),
+ ("QUIC port", "0"),
+ ("Hub", "https://example.invalid"),
+ ]
+ body = "".join(f"<tr><td>{k}</td><td>{v}</td></tr>" for k, v in rows)
+ return f"""
+ <table class="node-table node-table-overview">
+ <tbody>{body}</tbody>
+ </table>"""
+
+
def _audit_table():
head = "".join(f"<th>{c}</th>" for c in
("Time", "Event", "User", "IP", "Group", "Detail"))
@@ -65,6 +88,10 @@ FRAGMENT = textwrap.dedent(f"""
<div id="node" class="page-content node-page">
<h2>Node</h2>
<div class="node-group">
+ <h3 class="settings-heading">Overview</h3>
+ {_overview_table()}
+ </div>
+ <div class="node-group">
<h3 class="settings-heading">Audit</h3>
{_audit_table()}
</div>
@@ -87,6 +114,7 @@ FRAGMENT = textwrap.dedent(f"""
WIDTHS = [320, 360, 412, 768, 1024]
SELECTORS = ["#node.node-page", "#settings", "#node .node-table-scroll",
"#node .node-table-audit", "#node .node-group",
+ "#node .node-table-overview", "#node .node-key",
"#settings .settings-section"]
@@ -172,3 +200,29 @@ def test_the_audit_table_still_scrolls_itself_on_a_phone(measured, width):
page = _box(measured, width, "#node.node-page")
assert page["offRight"] == 0, (
f"{page['offRight']} px of the Node page is off a {width} px screen")
+
+
+@pytest.mark.parametrize("width", [320, 360, 412])
+def test_the_node_key_does_not_widen_the_page_on_a_phone(measured, width):
+ """The Overview table has no scroller of its own.
+
+ `.node-table-audit` may overflow because `.node-table-scroll` contains it.
+ Overview is a bare `.node-table` in a `.node-group`, so a cell that refuses
+ to wrap sets the column's minimum width and pushes the document itself
+ wider than the screen -- which detaches every `position: sticky` element on
+ the page from a viewport the reader can no longer see, the navigation bar
+ included. `.node-key` carries `word-break: break-all` for that reason;
+ remove it and this fails.
+ """
+ r = measured[str(width)]
+ assert r["docScrollW"] <= r["viewport"]["w"], (
+ f"the document scrolls to {r['docScrollW']} px on a {width} px screen "
+ "— the node key is pushing the page wider instead of wrapping")
+ table = _box(measured, width, "#node .node-table-overview")
+ card = _box(measured, width, "#node .node-group")
+ assert table["width"] <= card["width"], (
+ f"at {width} px the Overview table is {table['width']} px inside a "
+ f"{card['width']} px card — the key is driving the column")
+ key = _box(measured, width, "#node .node-key")
+ assert key["offRight"] == 0, (
+ f"{key['offRight']} px of the node key is off a {width} px screen")