diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index c8c0d4da6c..95d6240d22 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -381,6 +381,7 @@ jobs:
tests/test_no_direct_get_store_in_routes.py \
tests/test_moat_bug_class_v3_event_shape_gate.py \
tests/test_runtime_count_copy_sync.py \
+ tests/test_tab_template_page_wrapper.py \
tests/test_grok_bot_runtime_wiring.py \
tests/test_lovable_runtime_wiring.py \
tests/test_delegated_usage.py \
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c12205dbfa..0b5020cd6e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,10 @@
## Unreleased
+### Fixed: Guard panel drawn on top of every tab, stuck on "Loading..." (0.12.806 regression) (2026-09-03)
+- **Why:** 0.12.806 shipped the Guard tab (#5470) wrapped in `
`. The dashboard hides panels through `.page` and `#page-
`, and it has no rule for `tab-content`, so the Guard cards rendered above Home, Agents, Activity, Sessions, Cost and every other tab, frozen on "Loading..." because the loader keyed on a `#page-guard` element that did not exist. Selecting any runtime also hid the Guard nav item, since `guard` was in the per-runtime tab list but in no capability map and not marked node-wide.
+- **What:** (1) guard.html is a normal `.page` panel with id `page-guard`. (2) The 38 Guard stylesheet rules are scoped to `#page-guard` instead of the old id, so buttons, pills and tables style again. (3) `guard` joins `_CM_NODE_TABS`, next to Approvals and Alerts, so the nav item survives the runtime switcher; Guard ranks sessions from every runtime.
+- **Verified:** new `tests/test_tab_template_page_wrapper.py` (in the CI file list) fails on the shipped template and on an orphaned CSS scope, passes on the fix; browser check on a source boot: Home and Cost render without the Guard overlay, Guard loads its three cards styled, nav item present with Claude Code selected.
+
### Fix: sealed uploads are gzip-compressed before encryption, cutting the per-minute snapshot about 4x (carries #5472) (2026-09-03)
- **Why:** the wire audit of 0.12.802 measured a 1.2 to 1.4 MB sealed system snapshot every minute, about 2 GB a day per node. Ciphertext does not compress, and the snapshot cannot be skipped when idle (36 of its 80 keys change every cycle), so the only place to save the bytes is before the encryption step.
- **What:** `encrypt_payload` gzips the JSON before AES-GCM, but only once a heartbeat response has advertised `caps.blob_gzip`; until then every blob is byte-for-byte what it was. The reader recognises gzip by its magic bytes, which no JSON document can start with, so `decrypt_payload` and the published browser decryptor `cm-e2e.js` read both forms. Blobs under 4 KB (session titles) are never compressed. `CLAWMETRY_BLOB_GZIP=1|0` overrides the negotiation for self-hosted servers. The cloud advertises the codec per node and withholds it from any node with a paired desk device, whose firmware cannot inflate (clawmetry-cloud #2265, after this release is pinned).
diff --git a/clawmetry/static/css/dashboard.css b/clawmetry/static/css/dashboard.css
index badd13380f..115c09fa39 100644
--- a/clawmetry/static/css/dashboard.css
+++ b/clawmetry/static/css/dashboard.css
@@ -3408,38 +3408,38 @@ body.has-profile-menu #logout-btn { display: none !important; }
pills that were plain text. These definitions follow the existing
.inv-table / .card idioms and the shared token set, so Guard reads as
part of the dashboard rather than a bolted-on page.
- Scoped to #guard so short names cannot collide with other tabs. */
-#guard .section-header { margin-bottom: 18px; }
+ Scoped to #page-guard so short names cannot collide with other tabs. */
+#page-guard .section-header { margin-bottom: 18px; }
/* No global h2 rule exists and .section-header is used only here, so the tab
title inherited the browser default and rendered near-black on the dark
ground. Matches .inv-heading, the house style for a tab title. */
-#guard .section-header h2 {
+#page-guard .section-header h2 {
margin: 0; font-size: 19px; font-weight: 600; color: var(--text-primary);
letter-spacing: -0.01em;
}
-#guard .section-sub { color: var(--text-muted); font-size: 13px; line-height: 1.55; margin: 6px 0 0; max-width: 78ch; }
-#guard .card { margin-bottom: 16px; }
-#guard .card-head { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; }
-#guard .card-head h3 { margin: 0; font-size: 14px; font-weight: 600; color: var(--text-primary); }
-#guard .card-head .btn { margin-left: auto; }
-#guard .card-head .btn ~ .btn { margin-left: 0; }
+#page-guard .section-sub { color: var(--text-muted); font-size: 13px; line-height: 1.55; margin: 6px 0 0; max-width: 78ch; }
+#page-guard .card { margin-bottom: 16px; }
+#page-guard .card-head { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; }
+#page-guard .card-head h3 { margin: 0; font-size: 14px; font-weight: 600; color: var(--text-primary); }
+#page-guard .card-head .btn { margin-left: auto; }
+#page-guard .card-head .btn ~ .btn { margin-left: 0; }
-#guard .data-table { width: 100%; border-collapse: collapse; font-size: 13px; }
-#guard .data-table thead th {
+#page-guard .data-table { width: 100%; border-collapse: collapse; font-size: 13px; }
+#page-guard .data-table thead th {
text-align: left; font-size: 10px; text-transform: uppercase; letter-spacing: 0.5px;
color: var(--text-muted); font-weight: 600; padding: 8px 12px; white-space: nowrap;
border-bottom: 1px solid var(--border-primary);
}
-#guard .data-table tbody td {
+#page-guard .data-table tbody td {
padding: 10px 12px; border-bottom: 1px solid var(--border-secondary);
color: var(--text-secondary); vertical-align: middle;
}
-#guard .data-table tbody tr:last-child td { border-bottom: none; }
-#guard .data-table tbody tr:hover { background: var(--bg-hover); }
+#page-guard .data-table tbody tr:last-child td { border-bottom: none; }
+#page-guard .data-table tbody tr:hover { background: var(--bg-hover); }
/* Money and counts line up column-wise. */
-#guard .data-table td:nth-child(n+4) { font-variant-numeric: tabular-nums; }
+#page-guard .data-table td:nth-child(n+4) { font-variant-numeric: tabular-nums; }
-#guard .empty-state {
+#page-guard .empty-state {
padding: 22px 12px; text-align: center; color: var(--text-muted);
font-size: 13px; background: var(--bg-primary);
border: 1px dashed var(--border-primary); border-radius: 8px;
@@ -3447,50 +3447,50 @@ body.has-profile-menu #logout-btn { display: none !important; }
/* Status pills. pill-ok / pill-warn carry SEMANTIC state (running, flagged),
which is deliberately separate from the accent colour. */
-#guard .pill {
+#page-guard .pill {
display: inline-block; font-size: 11px; font-weight: 600; line-height: 1.6;
padding: 1px 9px; border-radius: 999px; white-space: nowrap;
background: var(--bg-secondary); color: var(--text-muted);
border: 1px solid var(--border-secondary);
}
-#guard .pill-ok { background: rgba(34,197,94,0.13); color: var(--text-success); border-color: transparent; }
-#guard .pill-warn { background: rgba(245,158,11,0.15); color: var(--text-warning); border-color: transparent; }
-#guard .pill-crit { background: rgba(239,68,68,0.15); color: var(--text-error); border-color: transparent; }
+#page-guard .pill-ok { background: rgba(34,197,94,0.13); color: var(--text-success); border-color: transparent; }
+#page-guard .pill-warn { background: rgba(245,158,11,0.15); color: var(--text-warning); border-color: transparent; }
+#page-guard .pill-crit { background: rgba(239,68,68,0.15); color: var(--text-error); border-color: transparent; }
-#guard .btn {
+#page-guard .btn {
font: inherit; font-size: 12px; font-weight: 500; cursor: pointer;
padding: 5px 11px; border-radius: 7px;
background: var(--button-bg); color: var(--text-secondary);
border: 1px solid var(--border-primary); transition: background 0.12s, color 0.12s;
}
-#guard .btn:hover { background: var(--button-hover); color: var(--text-primary); }
-#guard .btn:focus-visible { outline: 2px solid var(--text-accent); outline-offset: 2px; }
-#guard .btn-sm { font-size: 12px; padding: 4px 10px; }
-#guard .btn-xs { font-size: 11px; padding: 3px 8px; border-radius: 6px; }
-#guard .btn-primary { background: var(--bg-accent); border-color: var(--bg-accent); color: #fff; }
-#guard .btn-primary:hover { filter: brightness(1.08); color: #fff; }
+#page-guard .btn:hover { background: var(--button-hover); color: var(--text-primary); }
+#page-guard .btn:focus-visible { outline: 2px solid var(--text-accent); outline-offset: 2px; }
+#page-guard .btn-sm { font-size: 12px; padding: 4px 10px; }
+#page-guard .btn-xs { font-size: 11px; padding: 3px 8px; border-radius: 6px; }
+#page-guard .btn-primary { background: var(--bg-accent); border-color: var(--bg-accent); color: #fff; }
+#page-guard .btn-primary:hover { filter: brightness(1.08); color: #fff; }
/* Kill is irreversible; it reads as destructive before it is pressed. */
-#guard .btn-danger { color: var(--text-error); border-color: rgba(239,68,68,0.35); background: transparent; }
-#guard .btn-danger:hover { background: rgba(239,68,68,0.12); color: var(--text-error); }
-#guard td .btn + .btn, #guard td .btn + .muted { margin-left: 5px; }
+#page-guard .btn-danger { color: var(--text-error); border-color: rgba(239,68,68,0.35); background: transparent; }
+#page-guard .btn-danger:hover { background: rgba(239,68,68,0.12); color: var(--text-error); }
+#page-guard td .btn + .btn, #page-guard td .btn + .muted { margin-left: 5px; }
-#guard .muted { color: var(--text-faint); font-size: 12px; }
+#page-guard .muted { color: var(--text-faint); font-size: 12px; }
-#guard .form-row { display: flex; align-items: center; gap: 12px; margin-bottom: 9px; }
-#guard .form-row > label { flex: 0 0 190px; font-size: 12px; color: var(--text-muted); }
-#guard .form-row input, #guard .form-row select {
+#page-guard .form-row { display: flex; align-items: center; gap: 12px; margin-bottom: 9px; }
+#page-guard .form-row > label { flex: 0 0 190px; font-size: 12px; color: var(--text-muted); }
+#page-guard .form-row input, #page-guard .form-row select {
font: inherit; font-size: 13px; padding: 5px 9px; border-radius: 7px;
background: var(--bg-primary); color: var(--text-primary);
border: 1px solid var(--border-primary);
}
-#guard #guard-policy-form {
+#page-guard #guard-policy-form {
background: var(--bg-primary); border: 1px solid var(--border-primary);
border-radius: 10px; padding: 16px; margin-bottom: 14px;
}
-#guard .gp-step { display: flex; align-items: center; gap: 7px; font-size: 13px; color: var(--text-secondary); }
+#page-guard .gp-step { display: flex; align-items: center; gap: 7px; font-size: 13px; color: var(--text-secondary); }
-#guard .banner {
+#page-guard .banner {
display: flex; gap: 10px; padding: 11px 14px; border-radius: 9px;
font-size: 13px; margin-bottom: 16px; border: 1px solid transparent;
}
-#guard .banner-info { background: var(--bg-warning); color: var(--text-warning); border-color: rgba(245,158,11,0.3); }
+#page-guard .banner-info { background: var(--bg-warning); color: var(--text-warning); border-color: rgba(245,158,11,0.3); }
diff --git a/clawmetry/static/js/app.js b/clawmetry/static/js/app.js
index ed46856c49..db6761503b 100644
--- a/clawmetry/static/js/app.js
+++ b/clawmetry/static/js/app.js
@@ -12167,7 +12167,10 @@ var _CM_CAP_TABS = {
// inside Memory/Skills would be unreachable because the whole tab was
// hidden by _cmApplyRuntimeTabVisibility whenever a non-OpenClaw runtime
// was selected in the top-of-page runtime dropdown.
-var _CM_NODE_TABS = ['alerts','notifications','security','approvals','memory','skills'];
+// guard: one Guard view ranks running sessions from EVERY runtime by spend
+// at risk, and policies apply node-wide. It was in _CM_RT_ALL_TABS but in
+// no capability map, so selecting any runtime hid it (0.12.806 field hit).
+var _CM_NODE_TABS = ['alerts','notifications','security','approvals','guard','memory','skills'];
// Every togglable sidebar tab (so switching runtimes RE-SHOWS what a prior one
// hid). overview is never togglable.
var _CM_RT_ALL_TABS = ['flow','brain','models','tracing','turn-anatomy',
diff --git a/clawmetry/templates/tabs/guard.html b/clawmetry/templates/tabs/guard.html
index babd4eb228..8081bedaba 100644
--- a/clawmetry/templates/tabs/guard.html
+++ b/clawmetry/templates/tabs/guard.html
@@ -1,4 +1,4 @@
-