build_tmp_sort() encodes priority=true as '0' for ascending sort. JS comparators
were using b.localeCompare(a) (descending), inverting the encoding so priority=false
items sorted first. Fixed to a.localeCompare(b) in ae_journals_search_helpers.ts (3
sites in recovery_meetings +page.svelte and wrapper component).
Also fixes a Dexie anti-pattern in bb/[post_id]: .reverse() before .sortBy() is a
no-op in Dexie; moved array .reverse() to after the await.
Documents the encoding rule and legacy inverted-encoding modules in
GUIDE__SvelteKit2_Svelte5_DexieJS.md and adds mistake #15 to BOOTSTRAP quickstart.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two guards added to the trigger effect:
1. Gate on $slct.account_id being set — prevents the fetch from firing before
the bootstrap Sync Effect has propagated the real account_id. Without this,
get_object's localStorage scavenge read a stale account_id (e.g. 1 from a
prior dev/demo session) and the API returned the wrong account's record.
2. Stale-account detection — if liveQuery returns an IDB row with a non-null
account_id that doesn't match the current account, treat it as a cache miss
and fetch the correct record. Null (global/default) rows are still accepted.
Root cause: ae_loc is a persisted store that hydrates from localStorage before
the bootstrap Sync Effect runs. Old account-specific IDB rows scored highest in
the liveQuery sort, suppressing the trigger and leaving the wrong record visible
until the next full page refresh.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Three related fixes for the hide/show toggle in Pres Mgmt:
1. ae_events__event_session.ts: remove redundant search_query.and hide
filter and instead pass `hidden` to api.search_ae_obj as a URL param.
The backend StatusFilterParams defaults to hidden='not_hidden', so
without this the API always filtered to hide=0 regardless of intent.
2. pres_mgmt/+page.svelte (SCENARIO 2): capture qry_hidden as a
$derived.by dependency so the liveQuery instance is recreated on
toggle — prevents hidden sessions briefly appearing before the
debounce fires (blink fix).
3. pres_mgmt/+page.svelte (API call): use params.qry_hidden snapshot
instead of the live store to prevent race if user toggles during a
pending search.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Group should partition before priority in the sort chain, consistent with
how all other AE objects are sorted (group → priority → sort → ...).
Was accidentally omitted when switching to build_tmp_sort.
Full order: group → priority DESC → sort ASC → start_datetime ASC → code ASC → name ASC
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Creates src/lib/ae_core/core__idb_sort.ts with build_tmp_sort() — a shared
helper for computing tmp_sort_1/2/3 fields stored in Dexie. Fixes two bugs
present in all generic _process_generic_props implementations:
- priority encoded as 0/1 ASC (true sorted last); now inverted: true→'0'
- sort stored as unpadded string ("10" < "2"); now 8-char zero-padded
Applied to:
- ae_events__event_presentation: replaces inline specific_processor code
- ae_journals__journal + ae_journals__journal_entry: replaces manual formulas;
journal liveQueries (.reverse().sortBy()) updated to plain .sortBy() since
the inverted encoding handles direction without needing Dexie's .reverse()
Other modules (sessions, presenters, locations, posts, core) left unchanged
until their sort behavior is reviewed separately.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Compute presentation-specific tmp_sort_1/tmp_sort_2 in specific_processor,
overriding the generic values from _process_generic_props which had two bugs:
- priority encoded as 0/1 ASC (backwards — true should sort first)
- sort stored as unpadded string ("10" < "2" lexicographically)
- start_datetime and code not included (presentation-specific fields)
New encoding: priority(inv)_sort(8-padded)_start_datetime_code[_name]
Both liveQueries (Pres Mgmt session page, Launcher session view) now use
.sortBy('tmp_sort_2') — cleaner and uses the indexed field.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Location page now calls load_ae_obj_li__event_file on mount so files
appear immediately without requiring a manual Refresh press.
- _load_event_location_sub_data (Launcher 60s sync) now uses hidden='all'
with default limit (100) instead of hidden='not_hidden'/limit=25, which
was pruning valid Dexie records when Pres Mgmt and Launcher were both
open on the same location simultaneously.
- Removed the legacy launcher button (Send icon, /event/ path) from the
Locations list; removed unused Send icon import.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Same nuclear cache-clearing bug as the upload component fix. Clicking "Refresh
files" for one Location was wiping every event_file record from Dexie, leaving
all other Locations and Presenters with no files until their own background
syncs fired.
Now does a targeted load for the specific object only — same pattern as the
upload component commit.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Reverts the change from d1f5d0e2f that removed ae_loc preservation.
The tech help component is used across non-Launcher contexts where
users are authenticated normally and should not be signed out.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
menu_launcher_controls: handle_cache_cleanup now removes both ae_events_loc
and ae_loc from localStorage, giving a true clean slate on reload.
e_app_help_tech: Clear & Reload button no longer silently re-saves ae_loc
after clearing — if edit mode wipes localStorage, ae_loc goes with it.
Updated confirm message and title tooltip to say "you will be signed out"
instead of the previous misleading "sign-in will be preserved."
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Root cause: run_cmd uses exec() which blocks until the child exits. The
direct VLC binary forks its GUI process and exits — exec returns and the
post_script begins. The old post_script polled for VLC focus (up to 10s)
then sent Cmd+F, which fired mid-playback and stopped the video.
Fix 1 — nohup + &: detaches VLC from exec immediately so run_cmd returns
in ~0ms. This decouples the launcher flow from VLC's lifecycle.
Fix 2 — --fullscreen flag: VLC opens fullscreen directly via CLI option.
Eliminates the Cmd+F keystroke that was the proximate cause of the stop.
Fix 3 — > /dev/null 2>&1: silences VLC's verbose logging to prevent
exec's 1MB stdout buffer from overflowing and killing the process.
post_script simplified to a single `tell application "VLC" activate`
to bring VLC to the foreground after the 3s startup delay.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Tooltip now shows file size, created/updated timestamps, and open_in_os
setting alongside the existing SHA256 and hosted ID info.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- open_in_os='win' now routes to Windows launch profiles (pptxwin/pptwin/odpwin/pdfwin)
via WIN_EXTENSION_MAP in get_launch_profile() — was silently ignored before
- Display override migrated from non-existent cfg_json backend field to localStorage
($events_loc.launcher.file_display_overrides) — only visible in edit mode; TODO added
for proper backend column when event_file gains cfg_json
- Onsite mode WIN extension rename now covers all 4 types (pptx, ppt, odp, pdf)
instead of only pptx/ppt
- open_in_os button shows LoaderCircle spinner during API call
- Remove cfg_json from properties_to_save (column does not exist on event_file table)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
open_in_os = 'win': get_launch_profile() now maps pptx→pptxwin, ppt→pptwin,
odp→odpwin, pdf→pdfwin when open_in_os is 'win', routing to the Windows-variant
launch profiles (Parallels/CrossOver). Was never wired in native mode — feature
was silently lost in the MasterKey→Launcher port.
cfg_json missing from properties_to_save: the per-file display override was
always read as undefined from Dexie because cfg_json was never saved. Added
cfg_json to properties_to_save so display_override and any other cfg fields
persist correctly. NOTE: IDB_CONTENT_VERSIONS for event_file is not yet wired;
existing devices need a manual cache clear to pick up the new field.
Display override button: removed $ae_loc.is_native gate — must be configurable
from any device ahead of the event, not only on the podium Mac.
Display toggle persistence: quick_display_mode now reads from and writes to
$events_loc.launcher.display_mode so the last-set state survives page reloads
instead of always defaulting to 'extend'.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All app post-scripts called activate once before the poll loop, then only
checked `frontmost` passively. When Electron retains focus (common when the
app is spawned via run_cmd), macOS focus-stealing prevention blocks the one-
shot activate and VLC/PowerPoint/etc. never come to front. The poll loop
times out and fires the keystroke at Electron instead.
Fix: move activate inside the repeat loop so it re-fires every 0.5s until
macOS yields focus. Also bumped VLC post_delay_ms 1000→2000 and iterations
15→20 for slow conference machines.
Affected profiles: VLC (mac), PowerPoint (mac), LibreOffice (mac+win),
Acrobat (mac+win).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Onsite operators can now manually trigger a full pre-sync of all location
materials via a "Force Sync Location" button in the Launcher config.
This ensures podium Macs have all content cached before an event starts.
- Added trigger__force_location_sync to launcher session store.
- Implemented force_location_sync() in background sync engine to perform
recursive metadata fetches for all sessions in a location.
- Optimized download queue with a 4-tier chronological sort:
1. Event/Location assets (Global)
2. Sessions by start time (Earliest first)
3. Presentations by start time (Sequential order)
4. File creation date (First-in fairness for on-time uploads)
- Updated module and native integration documentation.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two gaps found during review of the recent retry-hardening commits:
1. api_patch_object.ts and api_delete_object.ts still defaulted to 60s
timeout while GET/POST were lowered to 20s. No callers set an explicit
timeout, so the default was the only value used. With retry_count=5 and
the new backoff policy, 60s per attempt = 5+ minutes worst-case wait.
Lowered to 20s to match GET/POST and keep worst-case under ~2 minutes.
2. api_delete_object.ts had no ae_auth_error import and no session-expired
banner on 401/403. A stale-session DELETE would silently return false
with no user feedback. Added browser + ae_auth_error imports and the
ae_auth_error.set() call matching the pattern in GET/POST/PATCH.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The Jan 2026 "offline-first fast-paths" commit (a10accfaa) inadvertently
broke retries for transient network failures (ERR_NETWORK_CHANGED, WiFi
roam events, etc.). The original code's .catch() returned undefined, which
fell through to the `if (!response) throw` path and correctly entered the
retry loop. After a10accfaa, .catch() returned the error as a value, and
the subsequent `instanceof Error` check returned false immediately —
bypassing all retries for the most common failure mode in
hotel/conference environments.
Changes:
- TypeError now throws into the retry loop instead of returning false
- AbortError still returns false immediately (intentional cancel, no retry)
- Per-attempt AbortController: moved inside the loop in both files so each
retry gets its own independent timeout (previously GET retries had no
timeout at all after the first attempt's clearTimeout ran)
- clearTimeout() added to catch block so timer is always cancelled on error
- Exponential backoff added: 2s→4s→6s→8s (capped) between attempts;
rapid retries on a flaky network accomplish nothing without a delay
- Default timeout lowered: 90s → 20s (generous for search/GET but avoids
the 90s worst-case hang that amplified ERR_NETWORK_CHANGED exposure)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- macOS: Uses direct binary path (/Applications/VLC.app/Contents/MacOS/VLC)
with --no-play-and-exit --play-and-pause flags and AppleScript fullscreen toggle.
Confirmed working: pause on last frame, stays in window.
- Linux: Uses shell command (vlc --no-play-and-exit --play-and-pause).
Known issue: not going fullscreen, not pausing on end. Deferred for later
investigation of flag interpretation vs launcher execution layer.
- Created separate profile constants: VLC_MIRROR_MAC_PROFILE and
VLC_MIRROR_LINUX_PROFILE in ae_launcher__default_launch_profiles.ts
- Updated TODO__Agents.md with Linux VLC issue for future debugging
Files: ae_launcher__default_launch_profiles.ts, documentation/TODO__Agents.md
`open -a App` returns immediately; a fixed delay is unreliable for cold starts.
Each post_script now polls every 500 ms (up to 7.5 s) until the target process is
frontmost before firing the automation keystroke. Keynote polls document count
instead of frontmost since start(front document) requires the file to be loaded.
Mac profiles: post_delay_ms 2000 → 1000. Win/Parallels profiles: 3000 → 1500.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Update default qry__limit to 100 in idaa_loc
- Add 75 to limit_steps in recovery meetings query component
- Bump AE_IDAA_LOC_VERSION to 2 to apply changes to existing users
- Update IDAA documentation and TODO__Agents.md with SQL optimization task
- Mark implemented UI/UX ideas as done in documentation
Wrap the data store element in an accordion-style toggle. State persists
in idaa_loc (localStorage) so the user's preference survives page reloads.
Added ds_info_collapsed field to idaa_local_data_struct.recovery_meetings.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Store Novi UUID list in event.mod_meetings_json.favorite so favorites
persist cross-browser without requiring Novi API write access. Optimistic
IDB update with API rollback on failure. Star button uses inline styles
to override Bootstrap v3 iframe CSS conflicts.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Root cause: stale IDB records from prior deploys persisted indefinitely.
Fast path returned 0 (account_id mismatch), API errored silently, and the
error state showed the same message as a genuinely empty result — making
the failure indistinguishable from real data.
Fix is layered defense:
- Bump IDB_CONTENT_VERSIONS.events.event to 2 (one-time force-clear for all users)
- Add check_and_clear_idb_table() helper to store_versions.ts; wire it in
(idaa)/+layout.svelte to catch future version mismatches on session start
- One silent auto-retry (3s) on API failure before surfacing error UI
- Distinct error state (Unable to load meetings) separate from empty state
- Escape-hatch cache-reset button after 8s when zero results + no active filters
- Document root cause and fix in README.md and BOOTSTRAP__AI_Agent_Quickstart.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two layout fixes for the badge_4x6_fanfold layout (no background_image_path):
1. badge_header max-height: 1.5in — the Axonius logo (624×232px) renders at
~1.49in tall at full badge width. The inherited max-h-[1.00in] was cropping
the bottom half of the image.
2. badge_body margin-top: 0 — overrides the component-level mt-54 (≈2.25in).
That margin was needed for the PVC layout where a full-bleed background image
covered the badge and body text needed to start in the image's designated zone.
For fanfold badges with a standalone header_path, mt-54 created a 2.25in blank
gap between the header and the attendee name.
Also updates default fit_heights for badge_4x6_fanfold to match the 4.0in body
height (was sized for 4.5in before the header zone was properly accounted for).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Introduces badge_layout_epson_4x6_fanfold.css (layout code badge_4x6_fanfold)
for the Axonius Adapt 2026 June show. Wires @page size to 4in×6in in the print
page and cleans up the stale 4in×12in default. Imports new CSS in badge component.
Measured stock: 4in × 6in portrait with 5/8in lanyard hole 1/4in from top.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Three redundant store fields encoding the same AM/PM choice replaced with a single
`use_12h: boolean` in PresMgmtLocState. iso_datetime_formatter gains a third param
(use_12h: boolean | null = null) that auto-resolves 24h↔12h format name variants via
a symmetric FORMAT_PAIRS lookup — null default leaves all ~100 existing call sites intact.
Toggle surfaces in three places: Clock icon in session time chip (hidden button, same
visual), event Options modal Display section, and session Options modal Display section.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
$idaa_trig is a key_val object (dict of boolean flags), not a string signal.
Adds update_zoom_full_url key to the store template and converts all 7
string comparisons/assignments to property access on the object.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Previously, searching by presenter name in pres_mgmt returned no results
because event_presenter_li_qry_str / event_presentation_li_qry_str were
never requested or stored.
Changes:
- ae_types.ts: add event_presentation_li_qry_str + event_presenter_li_qry_str
to ae_EventSession interface
- db_events.ts: same two fields added to Session Dexie interface
- ae_events__event_session.ts:
* add ft_presentation_search_qry_str param
* auto-upgrade view to 'alt' when either ft_presenter or ft_presentation
search is used (backend requires v_event_session_w_file_count for these)
* add both fields to properties_to_save so they persist to Dexie cache
- +page.svelte (pres_mgmt):
* pass ft_presenter_search_qry_str + ft_presentation_search_qry_str in API call
* local IDB fast path now checks both new fields
* client-side filter guard also checks both new fields
Two Svelte-side bugs causing account_name to always show 'Account Name Not Set':
1. ae_core__site.ts: background site_domain refresh only pushed cfg_json back
into $ae_loc after a stale cache hit. Now also pushes account_name and
account_code when the store holds a placeholder value.
2. +layout.ts: duplicate ae_loc_init['account_name'] assignment at line ~475
was overwriting the correct one at line ~385 with a different fallback string
('Account Name Not Set' vs 'Ghost Account'). Removed the duplicate.
Also includes user-intentional changes during testing:
- events/+page.svelte: typo fix ('You access' -> 'Your access'); Pres Mgmt /
Launcher / Badges / Leads buttons now gated on trusted_access && edit_mode
- events/+page.ts: event list limit 25 -> 7
- events/[event_id]/+page.svelte: user edit
Consistent with the tech help panel update — all Clear Storage / Clear & Reload
buttons now enumerate IDB databases dynamically so new modules are included
automatically without needing to update these lists.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Reworks Clear & Reload to use indexedDB.databases() (dynamic enumeration)
instead of a hardcoded DB list. Edit mode clears localStorage/sessionStorage
while preserving ae_loc (sign-in + permissions). Normal mode clears IDB only.
Adds new Full Reset button — wipes all IDB, localStorage, and sessionStorage
for the origin with no preservation. Useful for diagnosing quota/storage issues.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds check_and_clear_idb_tables() helper in core__idb_dexie.ts that clears
Dexie tables when their content version changes. Version numbers live in
IDB_CONTENT_VERSIONS (store_versions.ts); state tracked in localStorage
(ae_idb_ver__{module}__{table}) so each table clears exactly once per bump.
Wired into db_journals.ts (pilot): journal_entry at v3 clears stale
content_md_html/history_md_html data cached before the properties_to_save fix.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Mirrors the content_md_html/history_md_html fix on journal_entry.
description_md_html is computed from description via marked.parse() on
every background refresh and does not need to be persisted to IDB.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
QuotaExceededError on db_save was propagating through .then() into the
outer .catch(), which returned undefined and discarded the successfully-
fetched API data. Wrapped all db_save calls in try/catch so IDB failures
log a warning but never kill the load/create/update return value.
Also removed content_md_html and history_md_html from properties_to_save
— these are computed from content/history on every background refresh via
marked.parse(), so storing the rendered HTML alongside the source was
doubling storage cost per entry and the primary cause of quota exhaustion.
Affects: load, list, create, update, and qry functions in both journal
and journal_entry modules.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- electron_relay: add restore_macos_default_wallpaper() — uses run_osascript
to find first .heic in /System/Library/Desktop Pictures/ (version-agnostic)
- wallpaper cfg: Restore macOS Default button (native or edit_mode); clears
applied-URL tracking so next configured URL re-applies correctly
- wallpaper cfg: fix Apply Now / Save & Apply enabled when only external URL
is filled; display target becomes 'external' to leave built-in unchanged
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Stores wallpaper URL(s) in event_device.other_json.launcher.wallpaper and
auto-applies on all native Launcher instances within one heartbeat cycle (~60s),
eliminating manual per-Mac setup at events.
- electron_relay: typed set_wallpaper wrapper (url, url_external, display, auth headers)
- launcher_defaults: wallpaper_applied_url tracking + section_state__wallpaper
- launcher_cfg_wallpaper: new config section — save to device config + apply now
- launcher_cfg: add wallpaper section to device tab
- launcher_background_sync: auto-apply if config URL changed since last apply;
external-only config targets only the secondary display, leaving built-in unchanged
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>