fix(header): ship the tuning toggle hidden — no anonymous flash
#steering-toggle (the header 'Tuning' button) shipped visible in all six pages and was only removed after /api/whoami resolved, so anonymous visitors saw it flash for the whole round-trip (TODO.md L3). It now ships hidden on every page and initSharedHeader unhides it only for admin — the same ship-hidden / reveal-for-admin contract as the admin-only nav links; the anonymous end-state (removed from the DOM, phase-16 'absent, not hidden') is unchanged. Adds the story E2E suite (MutationObserver proves zero visible frames for anonymous on every page, admin reveal + panel + count badge, nav-contract regression) and the source-level unit pins. Also fixes test_steering.py's BASE_SCRIPT_COUNT (2 → 3: brand.js + markdown.js + app.js, since phase 39).
This commit is contained in:
@@ -26,10 +26,15 @@
|
||||
* list (newest-first, textContent-rendered, per-note delete, count
|
||||
* badge, the #steering-announcer live region) — so the toggle can
|
||||
* sit in every page's header with zero page-script duplication.
|
||||
* refreshSteering() / announceSteering() are exported for the chat
|
||||
* page's per-bubble Tune form (which stays in app.js); anonymous
|
||||
* visitors get the phase-16 "absent, not hidden" treatment (toggle
|
||||
* + panel removed from the DOM, /api/steering never fetched);
|
||||
* The toggle SHIPS hidden in every page (phase 40, 2026-08-27,
|
||||
* TODO.md L3 — the exact ship-hidden / reveal-for-admin contract
|
||||
* the admin-only nav links use: anonymous never sees it for a
|
||||
* single frame) and initSharedHeader unhides it only when whoami
|
||||
* says admin. refreshSteering() / announceSteering() are exported
|
||||
* for the chat page's per-bubble Tune form (which stays in app.js);
|
||||
* anonymous visitors get the phase-16 "absent, not hidden"
|
||||
* treatment (toggle + panel removed from the DOM, /api/steering
|
||||
* never fetched);
|
||||
* • the Sync sources state machine (phase 32, moved here from
|
||||
* sources.js in phase 34 task 02) — the §7.4 never-stale lifecycle
|
||||
* for #sync-btn (idle → running → success | failed): admin-only
|
||||
@@ -124,12 +129,15 @@ export async function initSharedHeader() {
|
||||
// same cached whoami (anonymous users never see it).
|
||||
if (syncBtn) syncBtn.hidden = !admin;
|
||||
// Phase 34: the steering controls (phase 15) are module-owned. Admin:
|
||||
// refresh the list so the count badge is right before the panel is
|
||||
// ever opened (fire-and-forget, as the chat page did before the move).
|
||||
// Anonymous: the toggle + panel are REMOVED from the DOM entirely —
|
||||
// the phase-16 contract says "absent", not just hidden — and
|
||||
// /api/steering is never fetched.
|
||||
// unhide the toggle — it SHIPS hidden (phase 40, 2026-08-27, TODO.md
|
||||
// L3, the same ship-hidden / reveal-for-admin contract as the
|
||||
// admin-only nav links) — then refresh the list so the count badge is
|
||||
// right before the panel is ever opened (fire-and-forget, as the chat
|
||||
// page did before the move). Anonymous: the toggle + panel are REMOVED
|
||||
// from the DOM entirely — the phase-16 contract says "absent", not
|
||||
// just hidden — and /api/steering is never fetched.
|
||||
if (admin) {
|
||||
if (steeringToggle) steeringToggle.hidden = false;
|
||||
if (steeringPanel) refreshSteering();
|
||||
} else {
|
||||
steeringToggle?.remove();
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
Postgres, read into every system prompt). The behavior is
|
||||
owned by the shared header module (assets/header.js); the
|
||||
#steering-panel section ships in every page's <main>. -->
|
||||
<button type="button" class="steering-toggle" id="steering-toggle"
|
||||
<button type="button" class="steering-toggle" id="steering-toggle" hidden
|
||||
aria-expanded="false" aria-controls="steering-panel">
|
||||
<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"><path d="M4 7h10M18 7h2M4 17h4M12 17h8"/><circle cx="15.5" cy="7" r="2.2"/><circle cx="9.5" cy="17" r="2.2"/></svg>
|
||||
<span class="steering-label">Tuning</span>
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
Postgres, read into every system prompt). The behavior is
|
||||
owned by the shared header module (assets/header.js); the
|
||||
#steering-panel section ships in every page's <main>. -->
|
||||
<button type="button" class="steering-toggle" id="steering-toggle"
|
||||
<button type="button" class="steering-toggle" id="steering-toggle" hidden
|
||||
aria-expanded="false" aria-controls="steering-panel">
|
||||
<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"><path d="M4 7h10M18 7h2M4 17h4M12 17h8"/><circle cx="15.5" cy="7" r="2.2"/><circle cx="9.5" cy="17" r="2.2"/></svg>
|
||||
<span class="steering-label">Tuning</span>
|
||||
|
||||
+1
-1
@@ -42,7 +42,7 @@
|
||||
Postgres, read into every system prompt). The behavior is
|
||||
owned by the shared header module (assets/header.js); the
|
||||
#steering-panel section ships in every page's <main>. -->
|
||||
<button type="button" class="steering-toggle" id="steering-toggle"
|
||||
<button type="button" class="steering-toggle" id="steering-toggle" hidden
|
||||
aria-expanded="false" aria-controls="steering-panel">
|
||||
<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"><path d="M4 7h10M18 7h2M4 17h4M12 17h8"/><circle cx="15.5" cy="7" r="2.2"/><circle cx="9.5" cy="17" r="2.2"/></svg>
|
||||
<span class="steering-label">Tuning</span>
|
||||
|
||||
+1
-1
@@ -45,7 +45,7 @@
|
||||
Postgres, read into every system prompt). The behavior is
|
||||
owned by the shared header module (assets/header.js); the
|
||||
#steering-panel section ships in every page's <main>. -->
|
||||
<button type="button" class="steering-toggle" id="steering-toggle"
|
||||
<button type="button" class="steering-toggle" id="steering-toggle" hidden
|
||||
aria-expanded="false" aria-controls="steering-panel">
|
||||
<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"><path d="M4 7h10M18 7h2M4 17h4M12 17h8"/><circle cx="15.5" cy="7" r="2.2"/><circle cx="9.5" cy="17" r="2.2"/></svg>
|
||||
<span class="steering-label">Tuning</span>
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
Postgres, read into every system prompt). The behavior is
|
||||
owned by the shared header module (assets/header.js); the
|
||||
#steering-panel section ships in every page's <main>. -->
|
||||
<button type="button" class="steering-toggle" id="steering-toggle"
|
||||
<button type="button" class="steering-toggle" id="steering-toggle" hidden
|
||||
aria-expanded="false" aria-controls="steering-panel">
|
||||
<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"><path d="M4 7h10M18 7h2M4 17h4M12 17h8"/><circle cx="15.5" cy="7" r="2.2"/><circle cx="9.5" cy="17" r="2.2"/></svg>
|
||||
<span class="steering-label">Tuning</span>
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
Postgres, read into every system prompt). The behavior is
|
||||
owned by the shared header module (assets/header.js); the
|
||||
#steering-panel section ships in every page's <main>. -->
|
||||
<button type="button" class="steering-toggle" id="steering-toggle"
|
||||
<button type="button" class="steering-toggle" id="steering-toggle" hidden
|
||||
aria-expanded="false" aria-controls="steering-panel">
|
||||
<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"><path d="M4 7h10M18 7h2M4 17h4M12 17h8"/><circle cx="15.5" cy="7" r="2.2"/><circle cx="9.5" cy="17" r="2.2"/></svg>
|
||||
<span class="steering-label">Tuning</span>
|
||||
|
||||
Reference in New Issue
Block a user