fix(idaa-recovery-meetings): fix priority sort, stale account_id gate, and cache clear

Three fixes for the IDAA Recovery Meetings load/display issues:

1. Sort direction: events use legacy encoding (priority ? 1 : 0), not build_tmp_sort.
   priority=true→'1' requires DESCENDING sort to put priority items first. The prior
   commit (ee79e33a2) incorrectly applied the build_tmp_sort-compatible ASC comparator
   to the events module, which does not use that encoding. Reverted in +page.svelte
   (both fast-path and API-results sort) and ae_idaa_comp__event_obj_li_wrapper.svelte.

2. Stale account_id gate: search $effect and handle_search_refresh now read
   $slct.account_id (set only by the bootstrap Sync Effect, reliable) instead of
   $ae_loc.account_id (persisted localStorage, may be stale from a prior session).
   Follows the mistake #14 pattern from BOOTSTRAP__AI_Agent_Quickstart.md.

3. Clear Cache & Reload: now enumerates and deletes ALL IDB databases via
   indexedDB.databases() (not just db_events.event), clears all localStorage and
   sessionStorage (not just two keys), and preserves the iframe reload URL for
   Novi re-authentication — matching the Full Reset pattern in e_app_help_tech.svelte.

4. IDB version bump: events.event → v3 (precautionary; flushes any stale cached
   event records on next user load in case prior deploys missed a bump).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Scott Idem
2026-06-03 17:54:05 -04:00
parent 74e0f752a6
commit a4fed750fa
3 changed files with 36 additions and 23 deletions

View File

@@ -86,7 +86,7 @@ export const IDB_CONTENT_VERSIONS = {
journal_entry: 3 // 2026-05-14: removed content_md_html + history_md_html from properties_to_save
},
events: {
event: 2, // Bumped 2026-05-16: force-clear stale IDB data causing "no meetings found" on IDAA
event: 3, // Bumped 2026-06-03: precautionary clear after sort-direction and account_id gate fixes
event_session: 1,
event_presenter: 1,
event_badge: 1,

View File

@@ -20,7 +20,7 @@ import {
idaa_slct,
idaa_trig
} from '$lib/stores/ae_idaa_stores';
import { ae_loc, ae_api } from '$lib/stores/ae_stores';
import { ae_loc, ae_api, slct } from '$lib/stores/ae_stores';
import { events_func } from '$lib/ae_events/ae_events_functions';
import Element_data_store from '$lib/elements/element_data_store.svelte';
@@ -135,8 +135,10 @@ function clear_filters() {
// This effect manages the orchestration between UI state and data fetching.
$effect(() => {
// 1. Reactive Dependencies
const account_id = $ae_loc.account_id;
if (!account_id) return; // Wait for account context
// Use $slct (non-persisted, set only by bootstrap Sync Effect) not $ae_loc
// (persisted, may hold stale account_id from a previous session in localStorage).
const account_id = $slct.account_id;
if (!account_id) return; // Wait for bootstrap to set account context
// Auth gate: do not fetch IDAA events for unauthenticated users.
// WHY $effect and not +layout.ts: layout load functions fire on SvelteKit link prefetch,
@@ -180,7 +182,7 @@ async function handle_search_refresh(qry_key: string) {
last_executed_key = qry_key;
const current_search_id = ++last_search_id;
const account_id = $ae_loc.account_id;
const account_id = $slct.account_id;
const remote_first = $idaa_loc.recovery_meetings.qry__remote_first;
if (!account_id) return;
@@ -253,11 +255,11 @@ async function handle_search_refresh(qry_key: string) {
(b.name ?? '').localeCompare(a.name ?? '')
);
} else {
// Robust Chronological Sort using pre-computed tmp_sort_1
// Handles Priority, Manual Sort, and the updated_on/created_on fallback
// tmp_sort_1 built by build_tmp_sort(): priority=true→'0', so ASC puts priority first.
// Events use legacy tmp_sort_1 encoding (ae_events__event.ts: priority ? 1 : 0),
// NOT build_tmp_sort's inverted encoding. priority=true→'1' > priority=false→'0',
// so DESCENDING sort puts priority items first.
local_results.sort((a, b) =>
(a.tmp_sort_1 ?? '').localeCompare(b.tmp_sort_1 ?? '')
(b.tmp_sort_1 ?? '').localeCompare(a.tmp_sort_1 ?? '')
);
}
@@ -336,9 +338,10 @@ async function handle_search_refresh(qry_key: string) {
(b.name ?? '').localeCompare(a.name ?? '')
);
} else {
// tmp_sort_1 built by build_tmp_sort(): priority=true→'0', so ASC puts priority first.
// Events use legacy tmp_sort_1 encoding (ae_events__event.ts: priority ? 1 : 0).
// DESCENDING sort puts priority=true ('1') items first.
api_results.sort((a, b) =>
(a.tmp_sort_1 ?? '').localeCompare(b.tmp_sort_1 ?? '')
(b.tmp_sort_1 ?? '').localeCompare(a.tmp_sort_1 ?? '')
);
}
@@ -465,7 +468,7 @@ if (browser) {
<Comp__event_obj_li_wrapper
{event_id_li}
link_to_type={'account'}
link_to_id={$ae_loc.account_id}
link_to_id={$slct.account_id}
limit={$idaa_loc.recovery_meetings.qry__limit}
{log_lvl} />
{:else}
@@ -508,14 +511,25 @@ if (browser) {
type="button"
class="btn btn-sm preset-tonal-surface preset-outlined-warning-100-900 hover:preset-filled-warning-200-800 transition-all"
onclick={async () => {
localStorage.removeItem('ae_loc');
localStorage.removeItem('ae_idaa_loc');
try { await db_events.event.clear(); } catch { /* ignore */ }
// Save the iframe reload URL first — it carries the Novi UUID + key
// params needed to re-authenticate after the cache wipe.
let reload_url: string | null = null;
try { reload_url = sessionStorage.getItem('idaa_iframe_reload_url'); } catch { /* ignore */ }
// Delete every IDB database on this origin (not just db_events.event).
try {
const saved_url = sessionStorage.getItem('idaa_iframe_reload_url');
if (saved_url) { location.href = saved_url; return; }
const db_list = await indexedDB.databases();
for (const db of db_list) {
if (db.name) indexedDB.deleteDatabase(db.name);
}
} catch { /* ignore */ }
location.reload();
// Clear all localStorage and sessionStorage. IDAA auth comes from
// the Novi UUID in the URL, not localStorage, so a full clear is safe.
localStorage.clear();
sessionStorage.clear();
if (reload_url) { location.href = reload_url; } else { location.reload(); }
}}>
<span class="fas fa-sync-alt m-1"></span>
Clear Cache &amp; Reload

View File

@@ -93,12 +93,11 @@ let lq__event_obj_li = $derived.by(() => {
(b.name ?? '').localeCompare(a.name ?? '')
);
} else {
// Robust Chronological Sort using pre-computed tmp_sort_1 (Refactored 2026-02-16)
// This handles Group > Priority > Manual Sort > Date (with updated_on fallback)
// tmp_sort_1 is built by build_tmp_sort() for ascending comparison:
// priority=true encodes as '0', priority=false as '1', so ASC puts priority first.
// Events use legacy tmp_sort_1 encoding (ae_events__event.ts: priority ? 1 : 0),
// NOT build_tmp_sort's inverted encoding. priority=true→'1' > priority=false→'0',
// so DESCENDING sort puts priority items first.
results.sort((a, b) =>
(a.tmp_sort_1 ?? '').localeCompare(b.tmp_sort_1 ?? '')
(b.tmp_sort_1 ?? '').localeCompare(a.tmp_sort_1 ?? '')
);
}
return results;