Files
OSIT-AE-App-Svelte/documentation/PROJECT__Stores_Svelte5_Migration.md
Scott Idem 98e31f1528 docs: update docs to reflect events store migration completion
BOOTSTRAP__AI_Agent_Quickstart.md: rewrite store reactivity trap section
to distinguish events sub-stores (PersistedState, fine-grained) from
ae_loc/idaa_loc (svelte-persisted-store, coarse). Add import/read/write
syntax examples and pointer to migration doc.

PROJECT__Stores_Svelte5_Migration.md: rewritten to reflect events module
fully complete; documents established PersistedState pattern with canonical
examples; tables show all 5 sub-stores done + events_loc retired.

TODO__Agents.md: events migration marked complete (2026-06-11); idaa_loc
and ae_loc listed as remaining work; stale events_loc file_display_overrides
ref fixed.

tests/README.md: replace Leads-only store migration note with full events
sub-store table, localStorage keys, and explanation of PersistedState
deserialization (no __version guard needed).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-11 16:50:06 -04:00

5.5 KiB

Project: Svelte 4 Store → Svelte 5 State Migration

Status: Events module — COMPLETE. Core / IDAA — In Progress (field cleanup done, PersistedState pending). Priority: High Created: 2026-03-30 | Last updated: 2026-06-11


Background

All core Aether stores were built with svelte-persisted-store (Svelte 4 contract). This provides coarse reactivity: any write to any field notifies all subscribers and re-serializes the entire object. For large stores like ae_loc and ae_events_loc, this caused unnecessary re-renders and was the root cause of the IDAA "Access Denied" corruption bug (a bootstrap write to ae_loc would overwrite authenticated_access if a persisted value was slightly different, corrupting IDAA member state stored in the same key).

The migration target: replace all persisted() stores with runed's PersistedState, which uses Svelte 5 fine-grained reactivity — a write to one field only triggers effects that read that field.


Completed: Events Module (2026-06-11)

All ae_events_stores sub-modules have been promoted to their own PersistedState stores and events_loc (the old persisted() store) has been fully retired.

Store File localStorage key Status
badges_loc ae_events_stores__badges.svelte.ts ae_badges_loc Done (2026-04-02)
leads_loc ae_events_stores__leads.svelte.ts ae_leads_loc Done (2026-04-03)
pres_mgmt_loc ae_events_stores__pres_mgmt.svelte.ts ae_pres_mgmt_loc Done (2026-04-03)
launcher_loc ae_events_stores__launcher.svelte.ts ae_launcher_loc Done (2026-06-11)
events_auth_loc ae_events_stores__auth.svelte.ts ae_events_auth_loc Done (2026-06-11)
events_loc (retired) ae_events_loc Store removed (2026-06-11)

ae_events_stores.ts now only exports events_sess (in-memory writable, no migration needed), events_slct, events_trig, events_trig_kv, events_trigger, and the EVENTS_MODULE_TITLE constant. The file no longer imports svelte-persisted-store.

store_versions.ts still calls _check_and_wipe('ae_events_loc', AE_EVENTS_LOC_VERSION) to clean old data out of users' browsers — this is intentional and should be kept for at least one year.


In Progress / Remaining: ae_stores.ts and ae_idaa_stores.ts

Both stores had their unused default properties pruned (2026-06-11), reducing migration scope:

ae_loc (in ae_stores.ts) — still persisted('ae_loc', ...):

  • Remaining fields: auth/identity, theme, permissions, ui config, file upload tracking, query prefs
  • This is the highest-impact remaining migration — used in nearly every route
  • Root cause of IDAA "Access Denied" bug (coarse write during bootstrap stomps on permission fields)

idaa_loc (in ae_idaa_stores.ts) — still persisted('ae_idaa_loc', ...):

  • Remaining fields: novi_uuid/verified/ts, novi_admin_li/trusted_li, archives/bb/recovery_meetings sub-objects
  • Fields pruned (2026-06-11): ds, idaa_cfg_json, top-level qry__*, novi_*_base_url, novi_rate_limited_until

Migration Pattern (Established)

Each sub-store follows this pattern, using the badges store as the canonical reference:

1. Defaults file (*_defaults.ts)

Define the shape and defaults as a plain TypeScript object (and interface if complex):

export interface BadgesLocState { ... }
export const badges_loc_defaults: BadgesLocState = { ... };

2. Store file (*.svelte.ts)

import { PersistedState } from 'runed';
import { badges_loc_defaults } from './ae_events_stores__badges_defaults';

export const badges_loc = new PersistedState('ae_badges_loc', badges_loc_defaults, {
    serializer: {
        serialize: JSON.stringify,
        // Merge with defaults so new fields added after first session get their defaults.
        deserialize: (raw: string) => ({ ...badges_loc_defaults, ...JSON.parse(raw) })
    }
});

3. Consumer syntax

// Import (note .svelte extension, not .svelte.ts):
import { badges_loc } from '$lib/stores/ae_events_stores__badges.svelte';

// Read:
badges_loc.current.fulltext_search_qry_str

// Write (fine-grained — only triggers effects that read this field):
badges_loc.current.fulltext_search_qry_str = 'hello';

// Bulk reset:
badges_loc.current = { ...badges_loc_defaults };

Key differences from old svelte-persisted-store pattern:

Old (persisted()) New (PersistedState)
Import import { events_loc } from '...ae_events_stores' import { badges_loc } from '...ae_events_stores__badges.svelte'
Read $events_loc.badges.field badges_loc.current.field
Write $events_loc.badges.field = x badges_loc.current.field = x
Reactivity Coarse — entire store notified Fine-grained — only affected fields
In $effect Subscribes to entire store Only subscribes to fields you read

Next Steps

  1. idaa_loc → PersistedState — Highest priority for IDAA stability. Promotes novi_uuid/verified, archives, bb, recovery_meetings sub-objects to their own stores following the same pattern. Primary benefit: eliminates the IDAA "Access Denied" corruption from ae_loc bootstrap writes.

  2. ae_loc → PersistedState — Largest scope (~every route in the app). Defer until after idaa_loc is done. Consider extracting auth_loc (the identity/permission fields) as the first sub-store since those are the fields implicated in the IDAA corruption bug.