From 4a704acc02cf76a2b928befd94a1e6823895d13c Mon Sep 17 00:00:00 2001 From: Dragan Spiridonov Date: Thu, 23 Jul 2026 10:41:11 +0200 Subject: [PATCH] =?UTF-8?q?fix(ui):=20actually=20call=20refreshSignInPanel?= =?UTF-8?q?=20=E2=80=94=20VERIFIED=20IN=20A=20REAL=20BROWSER?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `refreshSignInPanel` was exported and never invoked. The Cognitum Account panel would have rendered "Checking…" forever and the Sign in button would never have reflected a completed sign-in. That is the FOURTH defect of this exact shape today — implemented, unit-tested, and never called. The others: the refresh path no command invoked, scope resolved only at write time, and a WebSocket listener with no auth layer. The pattern is consistent: the logic was fine, the caller was missing, and a green suite could not see it. Now refreshed on every panel open — not once at construction — because the session may have been established in another tab or expired since page load. Buttons are also bound at construction so a click works before the first status fetch resolves. VERIFIED END TO END IN A REAL BROWSER (Chrome, http://127.0.0.1:8099/ui/), which is the gap that has been open all session: 1. panel showed "This server requires sign-in." + Sign in with Cognitum 2. clicked -> auth.cognitum.one -> approved 3. server: "browser sign-in complete" sub=ed3efb51-… 4. DevTools: ruview_session cookie on 127.0.0.1, Path=/, HttpOnly, SameSite=Lax 5. after reload the panel reads: "Signed in as UyShaIh1B1gL7km9Xli9kCDSdRT2 — sensing:read" + Sign out So the browser half of gate G-3 is now proven, not argued: PKCE, consent, the server-side code exchange, ES256 verification with audience and scope checks, the signed session cookie, and the UI reading it back. Diagnosis note worth keeping: the first attempt appeared to fail because the browser tab had been open since BEFORE the fix — an already-loaded ES module stays in memory regardless of `Cache-Control: no-store`. The cookie had been stored correctly the whole time; the panel simply never re-queried. The server log showed zero /oauth/status probes, which is what distinguished "fetch never fired" from "fetch got the wrong answer". Temporary cookie diagnostics added to find that are removed here. Tests: 547 sensing-server lib, unchanged. Co-Authored-By: Ruflo & AQE --- ui/utils/quick-settings.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/ui/utils/quick-settings.js b/ui/utils/quick-settings.js index 33c91212..7ae00f6b 100644 --- a/ui/utils/quick-settings.js +++ b/ui/utils/quick-settings.js @@ -113,6 +113,13 @@ export class QuickSettings { // Bind events this.panel.querySelector('.qs-close').addEventListener('click', () => this.close()); + // ADR-271 sign-in. Bound here as well as in refreshSignInPanel so a click + // works even if the status fetch has not resolved yet. + this.panel.querySelector('#qs-signin') + .addEventListener('click', () => { window.location.href = '/oauth/start'; }); + this.panel.querySelector('#qs-signout') + .addEventListener('click', () => { window.location.href = '/oauth/logout'; }); + this.panel.querySelector('#qs-reduced-motion').addEventListener('change', (e) => { document.body.classList.toggle('reduced-motion', e.target.checked); this.saveSetting('reduced-motion', e.target.checked); @@ -221,6 +228,11 @@ export class QuickSettings { open() { this.isOpen = true; this.panel.classList.add('open'); + // Refresh on every open, not once at construction: the session may have + // been established in another tab, or expired since the page loaded. + // Fire-and-forget — a failure renders as a message in the panel, and must + // not stop the panel opening. + void refreshSignInPanel(this.panel); } close() {