docs(handovers): D1 — move dated HANDOVERs to docs/handovers/ with rebrand-origin note
This commit is contained in:
255
docs/handovers/HANDOVER-2026-04-17.md
Normal file
255
docs/handovers/HANDOVER-2026-04-17.md
Normal file
@@ -0,0 +1,255 @@
|
||||
# Magnotia Session Handover — 2026/04/17
|
||||
|
||||
*Originally written when the product was named Kon (and briefly Corbie); references rewritten in the 2026-04-30 rebrand sweep.*
|
||||
|
||||
## Session Summary
|
||||
|
||||
Six-commit sprint executing the upgrade plan from
|
||||
`/home/jake/Documents/CORBEL-Furnished-House/output/reports/magnotia-upgrade-plan-2026-04-17.md`.
|
||||
Goal: get Magnotia from "core feature broken" to "ready to dogfood with friends."
|
||||
|
||||
## Commits
|
||||
|
||||
| Commit | Title |
|
||||
|---|---|
|
||||
| `96980c7` | Day 1 — fix mic capture: skip monitor sources, RMS validation, drop counting, list_devices, start_with_device |
|
||||
| `41db162` | Day 1 follow-up — wire user's microphone choice through start_native_capture + live session |
|
||||
| `19a6b83` | Day 2 — Codex follow-up hardening (channel disconnect, spawn_blocking, fallback silence guard, requeue counting, runtime error propagation) |
|
||||
| `69d768e` | Day 3 — global toast system + first error-toast wiring on DictationPage |
|
||||
| `1cce567` | Day 4 backend — FTS5 search + update_transcript + dictionary + paginated list + Tauri command surface |
|
||||
| `0e22ec5` | Day 4 frontend — dual-write history to SQLite + persist History rename |
|
||||
| `9f3be5c` | Day 5+6 — Settings → Vocabulary panel + Wayland self-relaunch |
|
||||
|
||||
## What changed
|
||||
|
||||
### Mic capture — now actually works
|
||||
|
||||
The HANDOVER from 2026/04/04 flagged native live transcription as broken
|
||||
(`Selected working microphone: null`, chunks repeatedly skipped as
|
||||
near-silence). Root cause was PulseAudio/PipeWire monitor sources
|
||||
(speaker loopback) winning the "first device that produces data within
|
||||
350ms" race — silent monitor sources delivered zero-valued bytes that
|
||||
satisfied that check.
|
||||
|
||||
Fixed by:
|
||||
|
||||
- **Skipping monitor sources** by name pattern (`.monitor` suffix,
|
||||
`Monitor of ` prefix, `loopback` substring)
|
||||
- **Validating by RMS energy** in a 350ms window, not just receipt
|
||||
of bytes
|
||||
- **Two-pass selection**: real inputs first, monitor sources only as
|
||||
last resort with explicit warning log + dead-silence floor (1e-7)
|
||||
guard so even fallback rejects all-zeros
|
||||
- **Verbose tracing** at every step
|
||||
- **Drop counter** (`Arc<AtomicU64>`) that tracks chunks lost to
|
||||
backpressure, including in the validation requeue
|
||||
- **Runtime error channel** so cpal stream errors after start succeeds
|
||||
surface to the live session for toast display
|
||||
- **`spawn_blocking`** wrapper so `start()`'s up-to-3.5s validation
|
||||
window does not freeze the async runtime
|
||||
|
||||
### Settings → Audio → Microphone picker
|
||||
|
||||
User can now explicitly pick which input device to use. Auto mode
|
||||
(empty) skips monitor sources and validates by RMS. Specific device
|
||||
opens it by exact name. Setting persists in `settings.microphoneDevice`
|
||||
(localStorage) and flows through to both `start_native_capture` and
|
||||
`start_live_transcription_session`.
|
||||
|
||||
### Toast system
|
||||
|
||||
`src/lib/components/ToastViewport.svelte` mounted in root layout.
|
||||
`toasts.error/warn/success/info(title, body)` from any component.
|
||||
Brand-palette colours (moss/signal/ember). aria-live polite + role=alert
|
||||
on errors. Honours `html.reduce-motion`. Sticky errors, auto-dismiss
|
||||
others.
|
||||
|
||||
First wired into DictationPage's "could not start recording" path. More
|
||||
pages can adopt it incrementally — `invokeWithToast` helper makes
|
||||
wrapping any Tauri call a one-liner.
|
||||
|
||||
### SQLite as canonical store
|
||||
|
||||
The transcripts table existed but no Tauri command read or wrote it
|
||||
(Codex caught this in the joint review). Now exposed via 10 new
|
||||
commands in `commands/transcripts.rs`:
|
||||
|
||||
- `add_transcript`, `list_transcripts` (paginated), `count_transcripts`,
|
||||
`get_transcript`, `update_transcript` (closes the long-standing
|
||||
rename-never-persists TODO from `architecture-review.md §13`),
|
||||
`delete_transcript`, `search_transcripts` (FTS5)
|
||||
- `list_dictionary_command`, `add_dictionary_entry_command`,
|
||||
`delete_dictionary_entry_command`
|
||||
|
||||
Frontend `addToHistory`, `renameHistoryEntry`, `deleteFromHistory` now
|
||||
dual-write to SQLite alongside localStorage. Best-effort: SQLite failure
|
||||
keeps the in-memory copy and warns to console. HistoryPage rename now
|
||||
calls `update_transcript`.
|
||||
|
||||
Migration v2 added FTS5 virtual table with porter+unicode61 tokeniser,
|
||||
diacritics-folded, plus INSERT/UPDATE/DELETE triggers to keep the FTS
|
||||
index in sync. Dictionary table also added in v2.
|
||||
|
||||
### Settings → Vocabulary
|
||||
|
||||
New collapsible section. Add custom terms (medication names, jargon,
|
||||
people's names) that the LLM cleanup prompt should preserve. Backed by
|
||||
the `dictionary` SQLite table. The LLM client itself is currently a
|
||||
stub; when wired, it imports `list_dictionary` from magnotia_storage and
|
||||
injects terms into the prompt suffix.
|
||||
|
||||
### Wayland self-relaunch
|
||||
|
||||
`ensure_x11_on_wayland()` runs before `tauri::Builder` on Linux. If
|
||||
`XDG_SESSION_TYPE=wayland`, sets `GDK_BACKEND=x11`,
|
||||
`WINIT_UNIX_BACKEND=x11`, `WEBKIT_DISABLE_DMABUF_RENDERER=1` so the
|
||||
HANDOVER env-var prefix is no longer needed.
|
||||
|
||||
## How to dogfood
|
||||
|
||||
### One-time setup on Menhir
|
||||
|
||||
```bash
|
||||
sudo dnf install cmake clang-devel
|
||||
cd /home/jake/Documents/CORBEL-Projects/magnotia
|
||||
npm install # if you have not already
|
||||
```
|
||||
|
||||
### Launch (no env-var prefix needed any more)
|
||||
|
||||
```bash
|
||||
cd /home/jake/Documents/CORBEL-Projects/magnotia
|
||||
npm run tauri dev
|
||||
```
|
||||
|
||||
If anything goes wrong on Wayland, you can still fall back to:
|
||||
|
||||
```bash
|
||||
env GDK_BACKEND=x11 WINIT_UNIX_BACKEND=x11 \
|
||||
WEBKIT_DISABLE_DMABUF_RENDERER=1 npm run tauri dev
|
||||
```
|
||||
|
||||
### What to test
|
||||
|
||||
1. **Mic capture happy path.** Open Settings → Audio. Devices populate.
|
||||
Pick your Blue Yeti (or whatever). Hit dictation. Speak. Text should
|
||||
appear within 2 seconds. Stop, save, the recording should appear in
|
||||
History.
|
||||
|
||||
2. **Mic capture failure path.** Pull the USB mic mid-recording. A toast
|
||||
should surface ("device disconnected" or similar). The session should
|
||||
not silently produce empty transcripts.
|
||||
|
||||
3. **Auto mode.** Clear the picker (set to "Auto"). Hit dictation. The
|
||||
logs (terminal where you ran `npm run tauri dev`) should show:
|
||||
- `[magnotia-audio] start: enumerated N input device(s)`
|
||||
- `[magnotia-audio] trying '...'` for each candidate
|
||||
- `[magnotia-audio] '...' validation: M samples, rms=...`
|
||||
- `[magnotia-audio] selected microphone: '...'`
|
||||
The selected mic should NOT be a `.monitor` source.
|
||||
|
||||
4. **History rename.** Make a recording. In History, rename it to
|
||||
something distinctive ("test rename 1"). Quit the app. Relaunch.
|
||||
Open History. The rename should still be there (was previously
|
||||
lost on relaunch — closes the old TODO).
|
||||
|
||||
5. **Vocabulary panel.** Settings → Vocabulary. Add "Wren" with note
|
||||
"CORBEL operating partner". Persists across restarts. (LLM cleanup
|
||||
prompt is a stub so the term won't actually affect transcripts yet —
|
||||
storage layer is ready for when LLM lands.)
|
||||
|
||||
6. **Toasts on error.** Try to hit dictation with no microphone
|
||||
connected at all. Should show a sticky error toast in the bottom-right
|
||||
("Could not start recording" + body) rather than failing silently.
|
||||
|
||||
### What's deferred (does not block dogfood)
|
||||
|
||||
- **Whisper pre-warm at startup.** Models still load on first dictation
|
||||
(~2-5s cold start). Deferred because it needs careful threading work
|
||||
to avoid blocking `setup()`. Easy to add later.
|
||||
- **Auto-updater (`tauri-plugin-updater`).** Deferred because it needs
|
||||
a release feed (GitHub releases or similar) which requires CI / signing
|
||||
infrastructure decisions.
|
||||
- **JACK monitor-name patterns.** Codex flagged that JACK setups may use
|
||||
different naming conventions than PulseAudio. Test on a JACK host,
|
||||
extend `is_monitor_name()` if needed.
|
||||
- **HistoryPage search via FTS5.** The infrastructure is in place
|
||||
(`search_transcripts` Tauri command) but HistoryPage still uses the
|
||||
in-memory client-side filter, which is fine for small histories.
|
||||
- **Read initial history from SQLite at boot.** Currently localStorage
|
||||
is the cold-start source; SQLite catches up via dual-write. A backfill
|
||||
/ one-time sync command can land later.
|
||||
|
||||
## Known limitations
|
||||
|
||||
- **The full Tauri build needs `cmake` + `clang-devel`** for
|
||||
whisper-rs-sys. Not a regression; pre-existing infra dep.
|
||||
- **State is still split** between localStorage (cache) and SQLite
|
||||
(canonical). Dual-write resolves the consistency problem in the
|
||||
short term. The eventual destination is SQLite-only with localStorage
|
||||
as a transparent cache.
|
||||
|
||||
## Cross-platform status (audited 2026/04/17)
|
||||
|
||||
| Platform | Build | Run | Polish | Confidence |
|
||||
|---|---|---|---|---|
|
||||
| **Linux x86_64 (Fedora 43, KDE Wayland)** | ✓ | ✓ | The everyday dev target | **HIGH** — this is what the sprint was developed against |
|
||||
| **Linux x86_64 (other distros, X11)** | Should work | Should work | Wayland self-relaunch is no-op on X11 sessions, evdev hotkeys may need user added to `input` group | **MEDIUM** — tested patterns, untested distros |
|
||||
| **Windows 10/11 x86_64** | Untested but should compile (CPAL + Tauri + whisper.cpp all support it) | Untested | Custom evdev hotkeys are no-op; falls back to Tauri's global-shortcut plugin which works on Windows | **LOW** — theoretically supported, has had zero hands-on testing |
|
||||
| **macOS aarch64 (Apple Silicon)** | Untested | Untested | Path bug fixed this commit (now uses `~/Library/Application Support/Magnotia/`); Info.plist needs `NSMicrophoneUsageDescription` for the app bundle | **LOW** — theoretically supported, has had zero hands-on testing |
|
||||
| **macOS x86_64 (Intel)** | Same as Apple Silicon | Same | Same | **LOW** |
|
||||
|
||||
**For the friends beta on Linux only**, this matters not at all. For a future Windows or macOS build, expect to spend a focused day or two debugging:
|
||||
|
||||
- Tauri config: `bundle.macOS.entitlements`, `bundle.windows.signingIdentity`
|
||||
- macOS code-signing + notarisation (real money: ~£75/yr Apple developer account)
|
||||
- Windows code-signing certificate (~£100-300/yr) or accept SmartScreen warning
|
||||
- whisper-rs-sys build dependencies per OS (cmake on all; Visual Studio Build Tools on Windows)
|
||||
- macOS-specific Info.plist keys for microphone permission
|
||||
|
||||
### What this sprint added on the cross-platform front
|
||||
|
||||
- `crates/storage/src/file_storage.rs::app_data_dir()` now correctly handles macOS (`~/Library/Application Support/Magnotia/`) and Linux (XDG-aware, `~/.local/share/magnotia`, with legacy `~/.magnotia` fallback for existing installs). Windows path unchanged.
|
||||
- New Tauri command `get_os_info` returns `{os, arch, family, usesCmd, isWayland, customHotkeyBackend, primaryModifierLabel}` so the frontend can adapt UI strings (Cmd vs Ctrl labels, "Open Finder" vs "Open Explorer", etc).
|
||||
- New `src/lib/utils/osInfo.js` helper: async `loadOsInfo()` warms a cache, then `isMac() / isWindows() / isLinux() / modKeyLabel() / isWayland()` are synchronous. Eagerly loaded at app startup in the root layout.
|
||||
- Falls back gracefully in browser-preview mode by reading `navigator.platform`.
|
||||
|
||||
## Files changed this sprint
|
||||
|
||||
```
|
||||
crates/audio/Cargo.toml
|
||||
crates/audio/src/capture.rs (rewrite + Day 2 hardening)
|
||||
crates/audio/src/lib.rs
|
||||
crates/storage/src/database.rs (+ FTS5, update, search, dictionary)
|
||||
crates/storage/src/lib.rs
|
||||
crates/storage/src/migrations.rs (+ migration v2)
|
||||
src-tauri/src/commands/audio.rs (+ device picker, spawn_blocking, M3 fix)
|
||||
src-tauri/src/commands/live.rs (+ microphoneDevice config field)
|
||||
src-tauri/src/commands/mod.rs
|
||||
src-tauri/src/commands/transcripts.rs (NEW — 10 Tauri commands)
|
||||
src-tauri/src/lib.rs (+ Wayland, command registrations)
|
||||
src/lib/components/ToastViewport.svelte (NEW)
|
||||
src/lib/pages/DictationPage.svelte (+ device wiring, error toast)
|
||||
src/lib/pages/HistoryPage.svelte (+ rename via update_transcript)
|
||||
src/lib/pages/SettingsPage.svelte (+ Audio + Vocabulary panels)
|
||||
src/lib/stores/page.svelte.js (+ microphoneDevice, dual-write)
|
||||
src/lib/stores/toasts.svelte.js (NEW)
|
||||
src/routes/+layout.svelte (+ ToastViewport mount)
|
||||
```
|
||||
|
||||
## Next steps after dogfood
|
||||
|
||||
1. Real-user feedback from one to three friends. What confuses them?
|
||||
What feels slow? What did they expect that did not happen?
|
||||
2. Address the deferred items in priority of feedback signal.
|
||||
3. Consider opening up the `magnotia-public-beta` channel — a single
|
||||
GitHub release with the auto-updater plumbed.
|
||||
4. The architecture review's other items (frontend test coverage,
|
||||
monolithic component split, hardcoded hex colours, ARIA gaps)
|
||||
become the "open beta polish" sprint.
|
||||
|
||||
---
|
||||
|
||||
*Compiled 2026/04/17 by Wren. Magnotia goes from "live transcription does not
|
||||
work" to "ready to put in front of one trusted friend." Six commits, no
|
||||
horrors so far.*
|
||||
73
docs/handovers/HANDOVER-2026-04-18.md
Normal file
73
docs/handovers/HANDOVER-2026-04-18.md
Normal file
@@ -0,0 +1,73 @@
|
||||
---
|
||||
name: handover-2026-04-18
|
||||
type: reference
|
||||
tags: [handover, session, magnotia]
|
||||
description: Session handover — 2026/04/18 dogfooding sprint
|
||||
---
|
||||
|
||||
# Magnotia Handover — 2026/04/18
|
||||
|
||||
*Originally written when the product was named Kon (and briefly Corbie); references rewritten in the 2026-04-30 rebrand sweep.*
|
||||
|
||||
## Current state
|
||||
|
||||
Phase 1 brand migration and Phase 2 polish are both **complete and committed**. Today was the first dogfood attempt — Vulkan GPU build is in progress but not yet confirmed working. Three bugs were caught and fixed during the first launch attempt.
|
||||
|
||||
## What's working
|
||||
|
||||
- **18/18 automated validation checks pass** (Playwright, `python3 /tmp/magnotia_validation.py`)
|
||||
- **Pre-warm fixed** — `tauri::async_runtime::spawn` instead of `tokio::spawn`; model loads in background before first dictation
|
||||
- **Preferences infinite loop fixed** — `Object.assign` mutation instead of object reassignment; Svelte 5 module state now stable
|
||||
- **DOM hydration fixed** — `applyToDOM` called on store init so `data-theme` is always set, even without Tauri webview injection
|
||||
- **Vulkan feature flag committed** — `whisper-vulkan` in `crates/transcription/Cargo.toml`
|
||||
- **`docs/dev-setup.md`** — authoritative dependency and launch reference
|
||||
|
||||
## What's left
|
||||
|
||||
### Immediate — Vulkan GPU build
|
||||
Vulkan build was not yet confirmed. Three system packages needed before it will compile:
|
||||
|
||||
```bash
|
||||
sudo dnf install vulkan-headers vulkan-loader-devel glslc
|
||||
```
|
||||
|
||||
Then launch:
|
||||
|
||||
```bash
|
||||
cd /home/jake/Documents/CORBEL-Projects/magnotia
|
||||
LIBCLANG_PATH=/usr/lib64/llvm21/lib64 npm run tauri dev
|
||||
```
|
||||
|
||||
Confirm GPU active in startup logs:
|
||||
```
|
||||
whisper_backend_init_gpu: device 0: NVIDIA GeForce RTX 4070
|
||||
```
|
||||
|
||||
### Manual validation (requires running app)
|
||||
Three items from the validation checklist that need real Tauri runtime:
|
||||
- [ ] Persistence test — set non-default zone/font, close, relaunch, verify zero flash
|
||||
- [ ] Cross-window preferences — open float/viewer windows, check they hydrate correctly
|
||||
- [ ] 90-second onboarding — fresh-model launch, first dictation under 90s
|
||||
|
||||
### Pre-release (before any build beyond Jake's machine)
|
||||
- [ ] Updater signing key — `tauri signer generate`, public key → `tauri.conf.json`, private key → CI secrets
|
||||
- [ ] ggml dedup — plan at `docs/superpowers/plans/2026-04-18-magnotia-ggml-dedup.md`, Option A (system-ggml shared lib), execute at Phase 3
|
||||
|
||||
## Gotchas discovered today
|
||||
|
||||
| Issue | Fix |
|
||||
|---|---|
|
||||
| `libclang` not on PATH | `set -Ux LIBCLANG_PATH /usr/lib64/llvm21/lib64` |
|
||||
| `tokio::spawn` panics in Tauri `setup()` | Use `tauri::async_runtime::spawn` — Tokio runtime isn't live yet during setup |
|
||||
| Svelte 5 `$effect` infinite loop on `updatePreferences` | Module-level `$state` must be mutated (`Object.assign`), never reassigned — stale references break loop guards |
|
||||
| Duplicate theme sync `$effect` in both `+layout.svelte` and `SettingsPage.svelte` | Removed from SettingsPage — layout handles it |
|
||||
| Vulkan build needs dev headers + shader compiler | `sudo dnf install vulkan-headers vulkan-loader-devel glslc` |
|
||||
|
||||
## Resume prompt
|
||||
|
||||
```
|
||||
Picking up Magnotia dogfooding from the 2026/04/18 session.
|
||||
HANDOVER is at HANDOVER.md in the project root.
|
||||
First job: confirm Vulkan GPU build compiles and check startup logs for RTX 4070.
|
||||
Then run the three manual validation items from the handover.
|
||||
```
|
||||
99
docs/handovers/HANDOVER-2026-04-19.md
Normal file
99
docs/handovers/HANDOVER-2026-04-19.md
Normal file
@@ -0,0 +1,99 @@
|
||||
---
|
||||
name: handover-2026-04-19
|
||||
type: reference
|
||||
tags: [handover, session, magnotia]
|
||||
description: Session handover — 2026/04/19 dogfood polish + cross-platform window chrome
|
||||
---
|
||||
|
||||
# Magnotia Handover — 2026/04/19
|
||||
|
||||
*Originally written when the product was named Kon (and briefly Corbie); references rewritten in the 2026-04-30 rebrand sweep.*
|
||||
|
||||
Second dogfood sprint. Four phases: (1) fix bugs surfaced on first real use, (2) redesign History for cognitive-load hygiene, (3) resolve broken window resize/drag on Linux Wayland, (4) clean up microphone picker.
|
||||
|
||||
## What shipped this session
|
||||
|
||||
### Cross-window preferences sync
|
||||
- `preferences.svelte.js` emits `magnotia:preferences-changed` Tauri event on update.
|
||||
- Main / viewer / float layouts listen and call `applyExternalPreferences` without re-emit, so theme and font changes propagate live across sibling windows.
|
||||
- Echo suppressed via source window label check.
|
||||
|
||||
### Hotkey recorder
|
||||
- Root cause of "can't change hotkey": button-level `onkeydown` relied on post-click keyboard focus, which webkit2gtk on Linux does not guarantee.
|
||||
- Fix: `document.addEventListener("keydown", ..., { capture: true })` inside a `$effect` gated by `recording`. Beats any descendant handler. Escape now cancels.
|
||||
|
||||
### History page redesign (research-backed)
|
||||
- Compact row now shows the **title** (or "Untitled"), not body-preview text — metadata already lives in the row columns (date, duration, source icon).
|
||||
- Expanded row gets an inline title input (replaces the old Rename prompt modal).
|
||||
- **Edit** button opens the viewer window in `edit` mode (editable textarea, debounced save to localStorage + storage-event sync back to main history).
|
||||
- **Export .md** copies a full YAML-frontmatter markdown document to the clipboard — paste into Obsidian.
|
||||
- **Tags**: `$lib/utils/frontmatter.js` exposes `deriveAutoTags` (currently returns `[]`), `buildFrontmatter`, `serialiseFrontmatter`, `buildMarkdown`. Manual tags stored as `item.manualTags`, rendered as removable chips in the expanded row with `+ add tag` input.
|
||||
- Header tag chip bar (cap 7, click to filter, × to clear), plus `tag:xyz` search syntax.
|
||||
- Global **Starred** filter toggle in the History header.
|
||||
- Research memo found all five previous auto-tag families redundant with existing row UI — kept the derivation hook for the post-Task-7 `topic:*` content tag from magnotia-llm.
|
||||
- Duplicate-transcript render fix: expanded `<p>` only if compact preview actually truncated.
|
||||
|
||||
### Viewer / editor popout
|
||||
- `/viewer` route now reads `magnotia_viewer_mode` from localStorage ("view" | "edit").
|
||||
- Edit mode renders a plain textarea bound to `item.text`; 400ms debounced save flushes on input, final flush on `onDestroy`. Segment-specific controls (Compact, Starred) hidden in edit mode.
|
||||
- Native title: **"Magnotia - Transcription Editor"**.
|
||||
|
||||
### Platform-aware window chrome (Linux fix)
|
||||
**Root cause:** Tauri v2 frameless `decorations: false` on KDE Wayland + webkit2gtk does not honour diagonal corner resize (collapses `NorthEast` etc. to a single axis via GTK's `gtk_window_begin_resize_drag`), and `data-tauri-drag-region` adds noticeable drag latency. Setting `setPointerCapture` ahead of `startResizeDragging` does not help once the compositor has taken over the pointer grab. Verified via Context7 docs + Codex diagnosis — Linux frameless is a known-fragile path.
|
||||
|
||||
**Fix:**
|
||||
- Linux uses **native KWin/Mutter decorations**. `src-tauri/tauri.linux.conf.json` overlays `decorations: true` + full main window config (title, sizes) — overlays **replace** the windows array, so every field must be present, not just the delta. `src-tauri/src/commands/windows.rs` uses `cfg!(target_os = "linux")` to set decorations per window.
|
||||
- macOS / Windows keep custom chrome. `src/lib/utils/osInfo.js` `isLinux()` gates `<Titlebar>` and `<ResizeHandles>` via `useCustomChrome = $state(false)`; flips to `!isLinux()` after `loadOsInfo()` resolves.
|
||||
- Dueling drag-region handlers removed across Titlebar, float page, viewer page — everywhere a manual `startDragging()` lives, the `data-tauri-drag-region` attribute was deleted (they're alternatives per Tauri docs, not combinable).
|
||||
- `ResizeHandles` kept for macOS/Windows frameless: 12 px edges / 20 px corners via CSS vars (`--magnotia-resize-edge`, `--magnotia-resize-corner`), `pointerdown` + `setPointerCapture`, corners with explicit higher z-index. Handles rendered as siblings of the animated layout div so `position: fixed` is viewport-relative rather than captured by the transform containing block.
|
||||
|
||||
### Window minimum sizes (evidence-backed)
|
||||
Research pass cited GNOME HIG (1024×600 desktop / 360×294 mobile floors), WCAG 2.2 SC 1.4.10 Reflow (320 CSS px), Raycast 750×474 as a reference for single-pane working width, and consistent A11y principle that nothing should clip in the default configuration.
|
||||
|
||||
| Window | Was | Now | Rationale |
|
||||
|---|---|---|---|
|
||||
| Main | 1020×540 | **960×600** | Fits 210 px sidebar + ~750 px content; GNOME vertical floor. |
|
||||
| Float | 400×400 | **360×480** | 360 = GNOME mobile floor; 480 fits pills + quick-add + sort + ~6 task rows without scroll. |
|
||||
| Transcript editor | 450×500 | **560×520** | Exceeds WCAG reflow floor; ~60-70 char measure for editing. |
|
||||
|
||||
### Microphone picker cleanup
|
||||
- ALSA enumeration was leaking `hw:`, `plughw:`, `front:`, `sysdefault:`, `null` et al into the dropdown.
|
||||
- `SettingsPage.svelte` now renders only sentinel devices (`default`, `pipewire`, `pulse`) + one entry per unique sound card, keyed off the `sysdefault:CARD=X` alias.
|
||||
- `crates/audio/src/capture.rs` reads `/proc/asound/cards` and populates a new `description` field on `DeviceInfo` with the card's full product string (e.g. "Blue Microphones" for Jake's Yeti). Frontend prefers description → CARD=X short name → raw name.
|
||||
|
||||
### GPU reporting
|
||||
- `commands/models.rs::get_runtime_capabilities` was hardcoded to `accelerators: vec!["cpu"]` and `supports_gpu: false` for whisper. Updated to `["cpu", "vulkan"]` and whisper `supports_gpu: true`, reflecting that `crates/transcription/Cargo.toml` links transcribe-rs with the `whisper-vulkan` feature unconditionally.
|
||||
- Settings now shows the Vulkan option instead of the "This build is CPU-only" notice.
|
||||
|
||||
### Desktop shortcut
|
||||
- `~/Desktop/Magnotia.desktop` launcher with the 128×128 icon, `Terminal=true` so logs are visible and Ctrl+C cleanly stops the run.sh wrapper.
|
||||
|
||||
## What's deferred
|
||||
|
||||
- **Transparent windows (`transparent: true`)** — Tauri issue #13270 reports this smooths drag/resize further on Linux, but it's moot now that Linux uses native decorations.
|
||||
- **File-system export (.md save dialog)** — currently clipboard-only. Needs a Rust `write_text_file` command for plugin-less file writes.
|
||||
- **Bulk select + bulk export** in History.
|
||||
- **LLM-powered content tags** (`topic:*`, `intent:*`) — slots into Task 7 `magnotia-llm` stub once Phase 3 wires real llama-cpp-2.
|
||||
- **Settings UX overhaul** — Jake flagged that current settings feel overwhelming. Proposed: bunch high-traffic settings, hide advanced behind a toggle. Brainstorm + plan deferred to a dedicated session.
|
||||
- **Task 7 (MicroSteps end-to-end)** — storage + Tauri CRUD + magnotia-llm stub + frontend dual-write all landed in an earlier commit chain. The MicroSteps UI was written as the final task 7 step but not yet dogfooded against the stub LLM. Needs manual walkthrough.
|
||||
|
||||
## Gotchas discovered today
|
||||
|
||||
| Issue | Fix |
|
||||
|---|---|
|
||||
| `tauri.linux.conf.json` stripped title and min sizes from main window | Overlay **replaces** the windows array — include every field, not just the delta |
|
||||
| `data-tauri-drag-region` + manual `startDragging()` on the same node caused drag latency | Pick one — we use manual `startDragging` for the button/input early-return logic |
|
||||
| Corner resize collapsed to single axis on KWin Wayland | Native decorations on Linux side-step the whole frameless path |
|
||||
| `animate-float-enter` on the viewer/float layout root created a containing block that broke `position: fixed` on ResizeHandles children | Render ResizeHandles as a sibling of the animated div, not a descendant |
|
||||
| Magnotia binary auto-respawned on file-save while a second run.sh was also launching → two visible instances sharing one Vite server | Do not script `./run.sh` while the user has already launched via the desktop icon; rely on HMR |
|
||||
| `run.sh` leaves `"beforeDevCommand": ""` in tauri.conf.json if its cleanup trap is bypassed (e.g. SIGKILL) | Cleanup trap restores `"npm run dev"` on graceful exit; SIGTERM (not SIGKILL) is the right kill signal |
|
||||
| `/proc/asound/cards` header lines have leading whitespace for 2-digit card ID alignment | Parser trims leading whitespace before checking for leading digit |
|
||||
|
||||
## How to resume
|
||||
|
||||
```
|
||||
Picking up Magnotia dogfooding from 2026/04/19.
|
||||
HANDOVER is at HANDOVER.md in the project root.
|
||||
Active priorities: (1) confirm resize/drag/mic cleanup, (2) Task 7 MicroSteps
|
||||
dogfood with magnotia-llm stub, (3) Settings UX brainstorm.
|
||||
```
|
||||
124
docs/handovers/HANDOVER-2026-04-24.md
Normal file
124
docs/handovers/HANDOVER-2026-04-24.md
Normal file
@@ -0,0 +1,124 @@
|
||||
---
|
||||
name: handover-2026-04-24
|
||||
type: reference
|
||||
tags: [handover, session, magnotia, phase-8, gamification]
|
||||
description: Session handover — 2026/04/24 Phase 8 forgiving gamification shipped end-to-end
|
||||
---
|
||||
|
||||
# Magnotia Handover — 2026/04/24
|
||||
|
||||
*Originally written when the product was named Kon (and briefly Corbie); references rewritten in the 2026-04-30 rebrand sweep.*
|
||||
|
||||
Phase 8 session. Executed the forgiving-gamification spec + plan written at the top of the session against `main`. Shipped 14 commits end-to-end. All automated gates clean; manual dogfood walkthrough still owed when Jake next opens the running app.
|
||||
|
||||
## Rebrand note
|
||||
|
||||
Product rename **Magnotia → Magnotia** still in flight. Copy in new docs is "Magnotia"; codebase paths / package names / repos still carry `magnotia`. No rebrand work this session. See `~/.claude/projects/-home-jake-Documents-CORBEL-Main/memory/project_magnotia_rebrand.md`.
|
||||
|
||||
## What shipped this session
|
||||
|
||||
### Phase 8 — forgiving gamification
|
||||
|
||||
Today's header now shows `Tasks · 3 today` alongside a 7-day momentum sparkline. No streaks, no grace days, no loss language. Commits on `main`, `729b82c` onwards:
|
||||
|
||||
| SHA | Summary |
|
||||
|---|---|
|
||||
| `2cc0697` | docs: design spec for Phase 8 |
|
||||
| `d5eb212` | docs: implementation plan for Phase 8 |
|
||||
| `729b82c` | migration v13, `auto_completed` column |
|
||||
| `92b3228` | cascade sets `auto_completed = 1` on parent |
|
||||
| `b992967` | style fix, drop em-dash from cascade comment |
|
||||
| `839754f` | `uncomplete_task` clears `auto_completed` |
|
||||
| `83bd338` | `list_recent_completions` storage fn + `DailyCompletionCount` + 5 tests |
|
||||
| `42b423e` | `list_recent_completions_cmd` Tauri wrapper |
|
||||
| `cb32285` | `DailyCompletionCount` type + `showMomentumSparkline` setting |
|
||||
| `4ffdae9` | `completionStats.svelte.ts` store |
|
||||
| `54ddd41` | `CompletionSparkline.svelte` component |
|
||||
| `3cadbb0` | badge + sparkline wired into Tasks header (+ `$derived` → getter fix) |
|
||||
| `c29720e` | emit `magnotia:task-uncompleted` + `magnotia:task-deleted` events |
|
||||
| `fa93033` | settings toggle for momentum sparkline |
|
||||
|
||||
### Counting semantics (locked)
|
||||
|
||||
- Manual top-level completions count.
|
||||
- Manual subtask completions count.
|
||||
- Cascade-completed parents (`auto_completed = 1`) do **not** count.
|
||||
- Uncompletions remove from the count on the spot.
|
||||
- Day boundaries are local time via `DATE(done_at, 'localtime')`.
|
||||
|
||||
### Architectural notes worth carrying forward
|
||||
|
||||
- **`serde` is now a dependency of `magnotia-storage`.** Added because `DailyCompletionCount` is serialised directly to the frontend via Tauri. The existing `TaskRow` → `TaskDto` split wasn't reused because the struct has no camelCase translation need (`day`, `count` are already frontend-friendly). Simpler, one fewer file to maintain.
|
||||
- **`$derived` cannot be exported at module scope in `.svelte.ts`.** Svelte 5 errors with `derived_invalid_export`. Originally hit during Task 9 integration; fix landed in the same commit (`3cadbb0`). `svelte-check` misses this; only Vite catches it. Plan/spec both mistakenly prescribed `$derived`; future stores should use `export function fooCount(): number` + `(...)` call sites, or a `$derived` wrapped inside a component script.
|
||||
- **Tuple `FromRow` in storage.** `magnotia-storage` strips sqlx's `derive` feature, so `#[derive(sqlx::FromRow)]` is not available. Use tuple `FromRow` `(String, i64)` etc. instead. Noted for future tasks in this crate.
|
||||
|
||||
## Verification state at session end
|
||||
|
||||
Fresh run on `main` tip `fa93033`:
|
||||
|
||||
- `cargo fmt --check`: clean.
|
||||
- `cargo clippy --all-targets -- -D warnings`: clean.
|
||||
- `cargo test`: **273 tests pass**, 0 failed, 0 ignored. Storage crate alone: 55 passed (6 new Phase 8 tests: column exists + default 0, cascade flag, uncomplete clear, 5-day series shape, cascade excluded, manual top-level counted, uncomplete excluded, local-day boundary).
|
||||
- `npm run check`: 0 errors, 0 warnings across 3955 files.
|
||||
- `npm run build`: clean production build via `@sveltejs/adapter-static`.
|
||||
|
||||
## Owed to Jake (next session)
|
||||
|
||||
1. **Manual dogfood walkthrough.** Cannot be driven by an automated agent. When opening Magnotia next:
|
||||
- Fresh state, no completions → header shows only "Tasks" title; no badge, no sparkline.
|
||||
- Complete one top-level task → badge "1 today"; sparkline appears.
|
||||
- Complete two more → badge "3 today".
|
||||
- Uncomplete one → badge "2 today".
|
||||
- Micro-step a task; complete its final subtask so the cascade closes the parent → badge increments by 1 (subtask), not 2.
|
||||
- Settings → Rituals → toggle sparkline off → sparkline disappears, badge remains.
|
||||
- Toggle on → sparkline returns.
|
||||
|
||||
2. **Phase 9 polish backlog items surfaced during review:**
|
||||
- Sparkline `aria-label` currently reads numeric list ("0, 1, 3, 2, 0, 4, 3"). Friendlier summary form ("3 completed today, 14 total over 7 days") would reduce screen-reader tedium. Not changed because spec prescribed the numeric list verbatim.
|
||||
- Per-day tooltip on sparkline hover was explicitly deferred to Phase 9 by the spec.
|
||||
- Motion curves / enter animations on badge + sparkline deferred to Phase 9.
|
||||
- Settings toggle currently co-located under "Rituals" section. Code reviewer flagged that placement reads as part of the "Launch at login" subgroup (the `border-t` above is visually claimed by a different setting). Two options for Phase 9 polish: wrap the sparkline toggle in its own `mt-4 pt-4 border-t border-border-subtle` subgroup, or move it to its own "Tasks" / "Progress" section. Rituals copy ("All off by default. Rituals only appear when you ask for them.") is mildly broken by the default-on sparkline; relocate the toggle rather than soften the copy.
|
||||
|
||||
3. **Plan quality note for future Phase 9+ plans.** Two patterns I prescribed turned out to be wrong on this codebase and only surfaced during execution:
|
||||
- `$derived` at `.svelte.ts` module scope: not supported.
|
||||
- `#[derive(sqlx::FromRow)]` in `magnotia-storage`: feature is stripped.
|
||||
|
||||
Worth a one-screen "magnotia-storage gotchas" reference file or at least a note at the top of future plans that touch these areas.
|
||||
|
||||
## What's left for v0.1
|
||||
|
||||
Unchanged except for Phase 8 now being closed:
|
||||
|
||||
| Phase | State |
|
||||
|---|---|
|
||||
| Phases 1 to 8 | **All shipped.** |
|
||||
| Phase 9 | Polish debt (file-system .md save dialog, bulk select/export in History, LLM content tags, settings UX pass, visual polish, accessibility sweep). Absorbs backlog above. 1 to 2 days. |
|
||||
| Phase 10a | QC: dogfood walkthrough, Rachmann's RB-08 Mac verification (parallel), cross-platform CI, a11y regression, clean-install test. Half day. |
|
||||
| Phase 10b | Magnotia → Magnotia rename sweep: package name, all 10 crates, bundle ids, install paths, `magnotia.db` → `magnotia.db`, event names, repo rename on both remotes. Half to 1 day. |
|
||||
| Phase 10c | Release: 0.1.0 version sync, CHANGELOG seeded from roadmap phases, release notes, tag + push. Half day. |
|
||||
|
||||
### Release-blocker state
|
||||
|
||||
- **0 open CRITICAL.**
|
||||
- **1 open MAJOR.** RB-08 `power-assertion-macos-objc2` (awaits Rachmann's manual runtime verification on his Mac: `pmset -g assertions` during a live session). Gates v0.1 tagging.
|
||||
|
||||
### Cargo.lock
|
||||
|
||||
- `Cargo.lock` is committed as of `b333c62` (Jake's hardening pass). Roadmap doc updated this session to reflect resolution.
|
||||
|
||||
## Repo state at session end
|
||||
|
||||
- `main` at `fa93033`.
|
||||
- 14 Phase 8 commits + 2 doc commits on top of yesterday's tip.
|
||||
- Local branches: `main` only.
|
||||
- `cargo build --workspace` green / `cargo test --workspace` green (273 passing) / `cargo clippy --workspace --all-targets -- -D warnings` 0 warnings / `cargo fmt --check` clean / `npm run check` 0/0 / `npm run build` clean.
|
||||
|
||||
## Anchors
|
||||
|
||||
- Spec: [docs/superpowers/specs/2026-04-24-phase8-forgiving-gamification-design.md](docs/superpowers/specs/2026-04-24-phase8-forgiving-gamification-design.md)
|
||||
- Plan: [docs/superpowers/plans/2026-04-24-phase8-forgiving-gamification.md](docs/superpowers/plans/2026-04-24-phase8-forgiving-gamification.md)
|
||||
- Roadmap: [docs/roadmap/2026-04-23-magnotia-feature-complete-roadmap.md](docs/roadmap/2026-04-23-magnotia-feature-complete-roadmap.md)
|
||||
- Previous handover: [HANDOVER-2026-04-19.md](HANDOVER-2026-04-19.md)
|
||||
- Release-blocker index: [docs/issues/README.md](docs/issues/README.md)
|
||||
- Rebrand memory: `~/.claude/projects/-home-jake-Documents-CORBEL-Main/memory/project_magnotia_rebrand.md`
|
||||
- Active-focus upstream: `context/active-focus.md` in CORBEL-Main
|
||||
Reference in New Issue
Block a user