Files
OSIT-AE-App-Svelte/documentation/PROJECT__AE_Events_PressMgmt_Config_Cleanup.md
Scott Idem e5c141e765 fix(pres_mgmt): config sync round 2 — save race, dead fields, launcher gate, version stamps
Four fixes found while tracing why Manager-saved Config page changes
(QR, POC column, etc.) weren't reliably reaching pres_mgmt_loc:

1. Config page save was a race, not deterministic. The save handler only
   called load_ae_obj_id__event() (SWR — returns stale Dexie cache
   immediately, refreshes in the background, not awaited) and assumed
   that "picked up the new config." It never called
   sync_config__event_pres_mgmt() itself. Now calls it directly with the
   just-saved draft, so the editing browser updates instantly with no
   race. Kept the load_ae_obj_id__event() call (default try_cache: true)
   for propagating to other browsers/tabs via Dexie — do not pass
   try_cache: false there, that skips the Dexie write entirely.

2. Removed the dead "Lock Config" Sync/Unlink toggle in the sign-in
   panel (e_app_access_type.svelte). It wrote to four fields
   ($ae_loc.lock_config/sync_local_config,
   pres_mgmt_loc.current.lock_config/sync_local_config) that are never
   read anywhere (confirmed via full-repo grep), and confusingly shared
   a name with the real, functional "Lock Config" checkbox on the Pres
   Mgmt Config page. Removed the button and the now-orphaned
   lock_config/sync_local_config fields from PresMgmtLocState.

3. show__launcher_link was never assigned by sync_config__event_pres_mgmt()
   — only its inverse hide__launcher_link was. The toggle button's
   `show__launcher_link || trusted_access` visibility gate (in 3 menu
   files) always collapsed to trusted-only, ignoring the admin's setting.
   Added the missing assignment.

4. AE_PRES_MGMT_LOC_VERSION was bumped to 2 this morning claiming it
   "forces a localStorage reset" — it didn't, because _check_and_wipe()
   was never wired up for ae_pres_mgmt_loc, and even if it had been, the
   store never wrote a __version field to compare. Fixed: the store's
   serializer now stamps __version, and store_versions.ts wires the
   check. Found and fixed the same bug already live in ae_leads_loc,
   except worse there — it was wiping leads users' local prefs on EVERY
   page load, not just once.

All logged in PROJECT__AE_Events_PressMgmt_Config_Cleanup.md.
svelte-check: 0 errors, 0 warnings.

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

18 KiB

Project: Pres Mgmt Config Cleanup & Config UI

Status: 🟡 ~70% Complete — Core Working, Cleanup Pass Needed Priority: Medium (core features functional; remaining work is deprecation + consistency) Created: 2026-04-02 Last Updated: 2026-06-12 (regression audit) Related: TODO__Agents.md, PROJECT__Stores_Svelte5_Migration.md


Background

The event.mod_pres_mgmt_json config grew organically across several conferences (LCI, BGH, etc.) and has accumulated serious inconsistencies:

  • Mixed show__ and hide__ prefixes for the same concepts
  • Some features have BOTH show__foo and hide__foo keys active simultaneously
  • Duplicate keys with different names (file_purpose_option_kv = file_purpose_option_li)
  • Dead config (HOLD__* prefix)
  • Type inconsistency (label__person_external_id: false vs "LCI member ID" string)
  • Keys in the DB not consumed by sync_config__event_pres_mgmt()
  • Bug: label__session_poc_name_short is read then immediately overwritten (line 970-972 in ae_events__event.ts)
  • hide_launcher_link / hide_launcher_link_legacy missing the __ separator (inconsistent)
  • show_content__presentation_description uses a third naming convention
  • Admin must edit DB records directly to change config — error-prone

The local config (events_loc.pres_mgmt) is also tangled into the main events_loc persisted store which is part of the paused Svelte 5 migration.


Goals

  1. Canonical config schema — define a TypeScript interface for mod_pres_mgmt_json
  2. Consistent naming convention — one rule for all show__/hide__ keys
  3. New Svelte 5 store — break out local pres_mgmt config from events_loc
  4. Config UI — admin page within pres_mgmt to manage the remote config
  5. No more direct DB edits for routine pres_mgmt configuration

Convention Decision

Rule: the prefix reflects the default state.

Prefix Default Use for
hide__ false = visible Features ON by default that can be turned off
show__ false = hidden Features OFF by default that can be turned on

Never have both show__foo and hide__foo for the same concept.

  • Visibility controls (codes, descriptions, POC, biography) → default visible → hide__
  • Opt-in features (access links, launcher, QR links) → default hidden → show__

Canonical Remote Config Schema

PressMgmtRemoteCfg — the authoritative TypeScript interface for event.mod_pres_mgmt_json:

interface PressMgmtRemoteCfg {
    // System
    lock_config: boolean;               // true = force remote→local sync (prevent user overrides)

    // Labels (event-specific terminology overrides)
    label__person_external_id: string | null;      // default: 'External ID'
    label__presenter_external_id: string | null;   // default: 'External ID'
    label__session_poc_type: string | null;        // e.g. 'champion', 'poc'
    label__session_poc_name: string | null;        // e.g. 'Champion', 'Point of Contact'

    // Codes (visible by default — hide to suppress)
    hide__location_code: boolean;
    hide__presentation_code: boolean;
    hide__presenter_code: boolean;
    hide__session_code: boolean;

    // Session fields (visible by default)
    hide__session_description: boolean;
    hide__session_location: boolean;
    hide__session_msg: boolean;
    hide__session_poc: boolean;
    hide__session_poc_biography: boolean;
    hide__session_poc_profile_pic: boolean;

    // Presenter fields
    hide__presenter_biography: boolean;

    // Presentation fields
    hide__presentation_datetime: boolean;
    hide__presentation_description: boolean;    // replaces show_content__presentation_description

    // Opt-in features (hidden by default — show to enable)
    show__copy_access_link: boolean;
    show__email_access_link: boolean;
    show__launcher_link: boolean;
    show__launcher_link_legacy: boolean;
    show__session_li_poc_field: boolean;   // POC column in session list/table; hide__session_poc still wins

    // Requirements
    require__presenter_agree: boolean;
    require__session_agree: boolean;

    // Navigation/UI constraints
    limit__navigation: boolean;
    limit__options: boolean;

    // File upload config
    file_purpose_option_kv: Record<string, {
        name: string;
        disabled?: boolean;
        hidden?: boolean;
    }> | null;

    // Report visibility (key = report slug, value = true to hide)
    hide__report_kv: Record<string, boolean>;
}

Keys Removed vs. Current DB Records

Removed Key Reason
file_purpose_option_li Duplicate of file_purpose_option_kv
HOLD__file_os_selection_option Dead/held feature
hide__copy_access_link Conflicts with show__copy_access_link — use show__
hide__email_access_link Conflicts with show__email_access_link — use show__
hide__launcher_link Conflicts with show__launcher_link — use show__
hide__launcher_link_legacy Conflicts with show__launcher_link_legacy — use show__
hide__report_li Superseded by hide__report_kv
show__navigation Ambiguous — covered by limit__navigation
label__session_poc_name_short Was a bug — never applied (overwritten immediately)
show_content__presentation_description Renamed to hide__presentation_description

New Svelte 5 Local Store

Do NOT touch events_loc or the paused Svelte 5 migration. Instead, create a standalone store for pres_mgmt local config.

File: src/lib/stores/ae_events_stores__pres_mgmt.svelte.ts

import { PersistedState } from 'runed';
import { pres_mgmt_loc_defaults } from './ae_events_stores__pres_mgmt_defaults';

export const pres_mgmt_loc = new PersistedState('ae_pres_mgmt_loc', pres_mgmt_loc_defaults);
// Usage: pres_mgmt_loc.current.hide__session_code
  • New localStorage key: ae_pres_mgmt_loc (separate from ae_events_loc)
  • Version gate: add AE_PRES_MGMT_LOC_VERSION to store_versions.ts
  • sync_config__event_pres_mgmt() writes to pres_mgmt_loc.current directly

Consumer syntax change:

BEFORE: $events_loc.pres_mgmt.hide__session_code
AFTER:  pres_mgmt_loc.current.hide__session_code

Config UI Page

Route: /events/[event_id]/(pres_mgmt)/pres_mgmt/config/ Access: $ae_loc.manager_access only Button visibility: Edit mode only ($ae_loc.edit_mode)

Page behavior

  • Loads event.mod_pres_mgmt_json fresh from API on page open
  • Displays grouped form sections (see below)
  • Save = load → merge → PATCH /v3/crud/event/{event_id} with { mod_pres_mgmt_json: updated }
  • The existing settings form at /events/[id]/settings has its pres_mgmt section removed or replaced with a link

Form sections (grouped)

  1. Systemlock_config
  2. Labelslabel__* fields (text inputs, nullable)
  3. Session Visibilityhide__session_* toggles
  4. Presenter Visibilityhide__presenter_* toggles
  5. Presentation Visibilityhide__presentation_* toggles
  6. Code Visibilityhide__*_code toggles
  7. Opt-in Featuresshow__* toggles
  8. Requirementsrequire__presenter_agree, require__session_agree
  9. Navigation Limitslimit__navigation, limit__options
  10. File Purpose Configfile_purpose_option_kv (JSON editor or structured form)
  11. Report Visibilityhide__report_kv (key-value toggles)

Migration Path

Safe and backward compatible — old DB records fall through to ?? false defaults.

  1. No DB migration script needed — old keys are simply ignored by the updated sync function
  2. Active events (BGH) get updated via the new UI after it's built
  3. The sync_config__event_pres_mgmt() rewrite is the critical step — it must handle the canonical keys and clean defaults before the UI ships

Implementation Steps

  • Step 1 — Define PressMgmtRemoteCfg TypeScript interface (new file or in ae_events__event.ts)
  • Step 2 — New ae_events_stores__pres_mgmt.svelte.ts with PersistedState ⚠️ Missing: version gate in store_versions.ts
  • Step 3 — Rewrite sync_config__event_pres_mgmt() in ae_events__event.ts to use canonical keys ⚠️ Issue: show__launcher_link_legacy hard-coded instead of synced from remote
  • Step 4 — Build config UI page at (pres_mgmt)/pres_mgmt/config/+page.svelte (manager_access + edit_mode gated)
  • Step 5 — Strip ae_comp__event_settings_pres_mgmt_form.svelte from settings page (or replace with a link to new page) BLOCKING
  • Step 6 — Migrate all $events_loc.pres_mgmt.* references in pres_mgmt templates to pres_mgmt_loc.current.*
  • Step 7 — Update BGH (and any other active events) via new UI (blocked on Step 5)
  • Step 8npx svelte-check clean; commit

Regression Fixes Needed (2026-06-12 Audit)

  • hide__launcher_link_legacy removed entirely (other agent's "config schema cleanup phase 2" commit, 2026-06-16) — Flask launcher is fully retired, no longer hard-coded or present anywhere in PressMgmtRemoteCfg / PresMgmtLocState / the sync function.
  • hide__launcher_link* / show__launcher_link local/remote conflict resolved (2026-06-16) — kept separate (they serve different purposes: hide__launcher_link gates the launcher link content, show__launcher_link gates the manual toggle button's visibility), but show__launcher_link was never actually assigned by sync_config__event_pres_mgmt() — only its inverse hide__launcher_link was. So the toggle button's show__launcher_link || trusted_access gate (in ae_comp__events_menu_opts.svelte, event_page_menu.svelte, location_page_menu.svelte) always collapsed to trusted-only, ignoring the admin's setting. Added the missing loc.show__launcher_link = ... assignment right next to hide__launcher_link in the lock-synced block.
  • AE_PRES_MGMT_LOC_VERSION properly wired into store_versions.ts (2026-06-16) — the other agent's commit bumped this constant to 2 claiming it "forces a localStorage reset," but _check_and_wipe() was never actually called for ae_pres_mgmt_loc, and even if it had been, the store's serializer never wrote a __version field for it to compare against — so the bump was a complete no-op. Fixed: ae_events_stores__pres_mgmt.svelte.ts's custom serializer now stamps __version on every write, and store_versions.ts calls _check_and_wipe('ae_pres_mgmt_loc', AE_PRES_MGMT_LOC_VERSION). Side effect: every browser's existing ae_pres_mgmt_loc (no __version ever written before) will wipe once on next load and resync clean from the remote config — this is expected and fine. Found the same bug already live in ae_leads_loc (actively wiping leads users' local prefs on every page load, not just once) and fixed it the same way — see ae_events_stores__leads.svelte.ts. badges_loc/launcher_loc/events_auth_loc have version constants declared but not wired into _check_and_wipe() at all (dormant, not actively harmful) — not fixed, flagged for whoever picks that up next.
  • POC column local/remote conflict fixed (2026-06-16)show__session_li_poc_field was local-only (never synced) and the session-list-table prop computation ignored the admin's hide__session_poc master switch entirely. Fixed: added show__session_li_poc_field to PressMgmtRemoteCfg + Config UI (Session Field Visibility) + sync_config__event_pres_mgmt() lock-synced block; list/table column visibility is now hide__session_poc || !show__session_li_poc_field in pres_mgmt/+page.svelte and locations/ae_comp__event_location_obj_li.svelte. The local per-browser "Show/Hide POC Column" toggle buttons in ae_comp__events_menu_opts.svelte and event_page_menu.svelte were removed — the field is lock-synced from the per-event Config page now, same as the other session field visibility toggles.
  • Presenter QR matched to session QR pattern (2026-06-16)show__session_qr / show__presenter_qr are the admin-set global default for everyone, signed in or not. show_content__*_qr is a trusted-staff-only local override, used when the admin has NOT enabled QR globally. The session QR side already worked this way (fixed earlier today); presenter QR was still on the old buggy logic requiring show_content__presenter_qr to be true even when the admin had enabled it for everyone, which non-trusted users (presenters) have no way to set. Fixed presenter_view.svelte (generation effect + display block) to show__presenter_qr || (trusted_access && show_content__presenter_qr). Also corrected two toggle-button visibility bugs found along the way: ae_comp__events_menu_opts.svelte was showing the QR toggle to all authenticated_access users (not just trusted) whenever the admin had enabled QR globally, even though the toggle had no effect for them; and presenter_page_menu.svelte's QR toggle was gated to administrator_access, hiding it from plain Trusted onsite staff entirely. Both now use the canonical pattern from session_page_menu.svelte: trusted_access && !show__*_qr.
  • Missing sync_config__event_pres_mgmt() calls on deep-link entry pages (2026-06-16) — root cause of the presenter QR bug above: a browser landing directly on the presenter page (e.g. via a presenter sign-in link) never synced remote config into pres_mgmt_loc.current at all, since only pres_mgmt/+page.svelte and session/[session_id]/+page.svelte called the sync function. Every "always synced" and "lock-synced" field (QR enables, POC visibility, code visibility, labels, etc.) silently stayed at hardcoded local defaults on that browser regardless of admin Config page settings. Added the same sync $effect (mirroring the existing comment/pattern in session/[session_id]/+page.svelte) to presenter/[presenter_id]/+page.svelte, locations/+page.svelte, location/[event_location_id]/+page.svelte, and reports/+page.svelte. Any new pres_mgmt page that can be a first-load entry point (i.e. not always reached via /pres_mgmt or /session/[id] first) needs this same block.
  • Config page save was a race, not deterministic (2026-06-16) — after PATCHing mod_pres_mgmt_json, the save handler only called load_ae_obj_id__event() (SWR — returns the stale Dexie cache immediately, refreshes from the API in the background, not awaited) and assumed that "picked up the new config." It never actually called sync_config__event_pres_mgmt() itself. Whether the editor's own browser reflected the change depended entirely on winning a race against an un-awaited background fetch — explains why specific just-changed fields (QR, POC column, profile-pic visibility, one report key) intermittently looked stale even to the admin who just saved them, while older unchanged fields stayed correct. Fixed: the save handler now calls sync_config__event_pres_mgmt({ pres_mgmt_cfg_remote: draft }) directly with the just-saved draft, so the editing browser updates instantly with no race. (Kept the load_ae_obj_id__event() call too, with its default try_cache: true — that's what propagates the fresh record to Dexie for other browsers/tabs. Do not pass try_cache: false there — that skips the Dexie write entirely, see the documented "try_cache: false Bug" in GUIDE__SvelteKit2_Svelte5_DexieJS.md.)
  • Removed dead "Lock Config" Sync/Unlink toggle (2026-06-16) — a Manager-only button in the sign-in panel (e_app_access_type.svelte) wrote to $ae_loc.lock_config/sync_local_config and pres_mgmt_loc.current.lock_config/ sync_local_config. Confirmed via full-repo grep that none of those four fields are read anywhere. It also confusingly shared the name "Lock Config" with the real, functional checkbox on the Pres Mgmt Config page (draft.lock_config, part of PressMgmtRemoteCfg, which actually gates sync_config__event_pres_mgmt()'s remote→local sync). Removed the button and the now-fully-orphaned lock_config/sync_local_config fields from PresMgmtLocState. Left $ae_loc.lock_config/sync_local_config (the general app store) alone — lock_config was never even in ae_loc's declared defaults (a phantom field created ad-hoc by the dead button), and ae_loc.sync_local_config is out of scope for a pres_mgmt-only pass; defer to the planned ae_loc migration in PROJECT__Stores_Svelte5_Migration.md.

Step 6 scope (mechanical find-replace)

The $events_loc.pres_mgmt pattern appears across:

  • ae_comp__event_session_obj_li.svelte
  • ae_comp__events_menu_opts.svelte
  • session/[session_id]/+page.svelte
  • session/[session_id]/session_view.svelte
  • session/[session_id]/session_page_menu.svelte
  • locations/locations_page_menu.svelte
  • reports/+page.svelte
  • pres_mgmt/+page.svelte
  • (and likely others — run grep -r 'events_loc.pres_mgmt' src/ to get full list)

Notes

  • The lock_config: true default means most events will always sync from remote. This is intentional — it prevents presenter laptops from drifting into different configs.
  • file_purpose_option_kv may need a structured editor (not raw JSON) to be usable. Consider a simple key-value form row per purpose type for Phase 2.
  • QR link keys (hide__presenter_qr_link, hide__session_qr_link) appeared in LCI config but are not in the canonical schema above. Evaluate whether they're actively used before adding them back.
  • limit__navigation and limit__options are in the DB but not currently read by sync_config__event_pres_mgmt(). Confirm where they're consumed before adding to sync.