From 932deced123ddcc092fe539006769cc36a4ed06b Mon Sep 17 00:00:00 2001 From: Scott Idem Date: Tue, 19 May 2026 19:47:46 -0400 Subject: [PATCH] docs: mark IDAA server-side Novi verification resolved in TODO__Agents.md All Access Denied root causes fixed and deployed 2026-05-19. 503 auto-retry regression also documented and fixed same session. Co-Authored-By: Claude Sonnet 4.6 --- documentation/TODO__Agents.md | 62 ++++++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/documentation/TODO__Agents.md b/documentation/TODO__Agents.md index e94c6b9e..de2ff30a 100644 --- a/documentation/TODO__Agents.md +++ b/documentation/TODO__Agents.md @@ -83,11 +83,17 @@ All known root causes fixed across 10+ commits to `src/routes/idaa/(idaa)/+layou Deploying as of 2026-05-19. Monitor for further member reports. #### All fixes applied +- [x] **Server-side Novi verification migrated (key fix for hotel/VPN/Cloudflare-filtered networks)** + `verify_novi_uuid()` now calls `GET /v3/action/idaa/novi_member/{uuid}` through the Aether + backend (server-to-server, Redis-cached 4h) instead of making a browser-to-Novi call. + Eliminates false Access Denied for members on hotel/conference WiFi, VPNs, and corporate + networks where the member's IP was rejected by Novi/Cloudflare. + Frontend: `(idaa)/+layout.svelte` | Backend: FastAPI `aether_api_fastapi` | Docs: `GUIDE__AE_API_V3_for_Frontend.md` §12, `CLIENT__IDAA_and_customized_mods.md` +- [x] Novi TTL extended to **12 hours** (5 min → 45 min → 12 h) — covers a full conference day - [x] Access Denied on iframe reload (sessionStorage URL preservation) — `2855e091f` - [x] TTL cache bypassed when `$ae_loc` auth flags reset — `2855e091f` - [x] "Verification Unavailable" screen distinct from "Access Denied" — `2855e091f` - [x] "Try Again" without page reload (`retry_count` pattern) — `2855e091f` -- [x] Novi TTL extended to 45 minutes (from 5) — `2855e091f` + manual edit - [x] 12 s AbortController hard timeout on Novi fetch — `e921ca973` - [x] Network/AbortError gets 3 s grace + one retry — `e921ca973` - [x] Clear Cache & Reload added to Access Denied state (iframe mode) — `2855e091f` @@ -111,6 +117,60 @@ below. The TTL + `verify_in_flight` guards are the current mitigation. --- +### [IDAA] Server-side Novi verification — 503 not auto-retried (regression, 2026-05-19) + +**File:** `src/routes/idaa/(idaa)/+layout.svelte` → `verify_novi_uuid()` + +**Bug:** After migrating to the Aether server-side proxy, a `503` response (Novi unreachable / +Novi 5xx) skips the automatic retry that exists for network-level errors. + +**Root cause:** The auto-retry branch only fires for `TypeError` and `AbortError`: +```ts +const is_network_or_timeout = + error instanceof TypeError || + (error instanceof Error && error.name === 'AbortError'); +if (is_network_or_timeout && !is_retry) { + // 3s wait → retry +} +``` + +In the old client-to-Novi flow, an unreachable Novi server produced a `TypeError: Failed to +fetch` — caught above, auto-retried. In the new flow the Aether server returns a clean HTTP +`503`, which hits `!response.ok` → `throw new Error(...)` — a plain `Error`, not `TypeError`. +`is_network_or_timeout` is `false` → no retry → `verify_failed_for_uuid` latch is set +immediately → user sees "Verification Unavailable" requiring a manual "Try Again" click for +what may be a 2-second Novi hiccup. + +**Fix:** Add a `503` check before the generic `!response.ok` throw (or after), applying the +same 3-second wait + one retry that network errors get: +```ts +if (response.status === 503) { + if (is_retry) { + throw new Error(`Novi verification: Novi unreachable (503) — retry also failed`); + } + console.warn(`IDAA Layout: Novi unreachable (503) for ${uuid}. Retrying in 3s...`); + verifying_status_msg = 'Connection issue — retrying...'; + await new Promise((resolve) => setTimeout(resolve, 3_000)); + await verify_novi_uuid(uuid, true); + return; +} + +if (!response.ok) { + throw new Error(`Novi verification returned ${response.status} for UUID ${uuid}`); +} +``` + +**Catch block:** After the retry, if 503 still fires, it throws a plain `Error` → caught → +`is_network_or_timeout = false` → `verify_error_type = 'api_error'` → "Verification +Unavailable". This is correct — after two attempts the UI should tell the user. + +**Note on `verify_error_type` reset:** The recursive retry call resets `verify_error_type = +null` at its top before checking the response. For 429 this is harmless (re-set on 429 check). +For 503 after this fix it is also harmless — 503 is caught before `!response.ok`. Worth knowing +if modifying the flow further. + +--- + ### [Stores] Svelte 4 → Svelte 5 State Migration (prerequisite for Phase 2c) The app uses `svelte-persisted-store` (Svelte 4 store contract) for all core persisted state (`ae_loc`, `idaa_loc`, `ae_api`, `ae_sess`, etc.). In Svelte 5 `$effect`, reading **any field**