Commit Graph

77 Commits

Author SHA1 Message Date
62e795174c v0.3 Phase 5g: quietware default-on for branch builds
The headless screenshots from Phases 4 and 5 had VITE_LUMOTIA_QUIETWARE=1
set at capture time; the running Tauri dev/release builds did not. Result:
21 commits of design work were invisible in the actual app even though the
emailed screenshots showed v0.3.

Fix is one-line: invert the env-var check in src/routes/+layout.svelte so
data-design="quietware" is the default on this branch. Explicit opt-out via
VITE_LUMOTIA_QUIETWARE=0 still works for anyone who wants to see the v0.2
surface for comparison.

Behaviour:
  unset → quietware ON
  "1"   → quietware ON (same as unset)
  "0"   → v0.2 surface forced

Branch-only default for now. Merge to main can decide whether to keep this
or require explicit opt-in once v0.3 stabilises.
2026-05-15 20:32:07 +01:00
4de3acd426 v0.3 Phase 5c: Dictation layout migration toward the mockup structure
Layout work, not a colour pass. DictationPage's existing 1 282-LOC
structure stays untouched for v0.2; under quietware a new layout
renders via LumotiaPageSkeleton with five zones matching the mockup:

  Capture header   large Record + status + secondary support + timer + pill
  Slim notice      info-classed browser-preview or danger-classed errors
  Primary surface  calm transcript canvas with empty-state typography
  Action bar       Copy / Save / Extract Tasks / Template / Open Viewer
  Mono metadata    Smart · model · Local-only or Browser-preview

Implementation pattern. Gated {#if isQuietware} branch inside the
existing {#if needsDownload}{:else} structure. The new layout
subscribes to ALL existing state bindings (page.recording,
page.timerText, transcript, error, tauriRuntimeAvailable, modelLoading,
settings.*, etc.) and reuses every existing handler:
  toggleRecording, copyAll, saveTypedText, manualExtractTasks,
  applyTemplate, invoke("open_viewer_window")

v0.2 surface unchanged — when data-design="quietware" is absent the
existing control-strip / toolbar / post-capture-card layout renders
as before.

Capture-header.

  - Record button (72 px circular) carries the role-correct
    --button-record-bg (red). Recording state pulses; modelLoading
    shows spinner; non-Tauri state neutral-disabled.
  - Status text uses Young Serif italic. Four states map to
    "Ready to capture" / "Loading model" / "Desktop preview mode"
    / "Recording…".
  - Secondary support text in Work Sans body weight, adapts per state.
  - Timer in JetBrains Mono tabular-nums, right aligned.
  - Status pill appears when useful (recording / transcribing / ready).

Slim notice.

  - Browser-preview renders LumotiaNotice tone="info" slim dismissible
    with the friendly Phase 5b copy.
  - Real errors render tone="danger" slim dismissible.
  - Slot stays empty otherwise — no permanent banner clutter.

Transcript surface.

  - Empty state: 56-px Mic icon, Young Serif italic
    "Talk now, think later.", Work Sans support "Press record, or
    Ctrl+Shift+R." Centred, low-emphasis tertiary text on the calm
    card surface.
  - Populated: scrollable transcript at the user's accessibility
    transcript-size preference.

Bottom action bar.

  - Copy (tertiary), Save (primary blue), Extract Tasks (secondary),
    Template (secondary, applies templates[0] when present), Open
    Viewer (secondary, gated on Tauri).
  - All disabled until transcript has content. Disabled controls
    render neutral with no wireline per the Phase 4k token contract.

Mono metadata footer.

  - Left: "Smart · {model} · Local only" or "Browser preview".
  - Right: "{formatMode} · {activeProfile}".
  - JetBrains Mono, text-tertiary, single line, below the action bar.

What's preserved (no behaviour change).

  - Recording events, hotkey listeners (lumotia:toggle-recording).
  - Tauri runtime branching (tauriRuntimeAvailable, browser-preview state).
  - Live preview hooks (emit("preview-listening") etc.).
  - Task extraction (manualExtractTasks -> extractTasksForTranscript).
  - Template apply (applyTemplate(template)).
  - Copy / Save paths (copyAll, saveTypedText).
  - All existing state bindings on page.*, settings.*, prefs.*.

Out of scope for this commit (queued for follow-up).

  - Files / Tasks / History page migrations (Phases 5d-5f).
  - Real Lumotia wordmark / icon integration (Phase 6).
  - Motion audit (Phase 7).
  - Full Template-picker menu (currently auto-applies templates[0]).

Verified.

  - npm run check: 0 errors, 0 warnings across 5707 files.
  - Headless-Chromium screenshots confirm the new layout renders
    correctly in quietware-dark and quietware-light with the
    disabled-record state (Tauri APIs absent in browser preview),
    slim info notice, and empty-state typography.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 16:14:12 +01:00
b9dd598937 v0.3 Phase 4k: palette architecture hardening — scales + component tokens + contrast check
Token-hardening pass per round-9 redirect. No new visual decisions —
just plumbing the tokens correctly so the colour grammar locked in
Phase 4j has a system underneath instead of hand-tuned hex.

Scales.

  NEW: src/design-system/v0.3-quietware-scales.css. 11-step tonal
  scales (50, 100, ..., 900, 950) for five source hues and their five
  complement sources. Saturation drops at extremes to avoid neon
  highs and washed-out lows. Hue-stable lightness curve picked to
  mimic Material 3 / IBM Carbon tonal scales.

  Generated by scripts/generate-quietware-scales.py (committed) so
  values are reproducible. To regenerate:
    python3 scripts/generate-quietware-scales.py > scales.css

  Wired into src/app.css directly before v0.3-quietware-tokens.css.

Component tokens consume scale references only.

  All --button-{role}-{tier} and --progress-{state}-fill tokens now
  read from var(--{hue}-{step}) instead of raw hex literals. Future
  scale tuning happens in one place; component callers never change.

    --button-record-bg:    var(--red-600)
    --button-primary-bg:   var(--blue-700)
    --button-success-bg:   var(--green-800)   /* darkened so white
                                                  text clears AA */
    --button-caution-bg:   var(--yellow-400)
    --button-neutral-bg:   var(--color-bg-elevated)
    --button-disabled-bg:  var(--color-bg-elevated)
    --brand-accent:        var(--orange-500)

Progress component tokens.

  New family: --progress-{download,transcribing,success,caution,danger,
  disk,disk-caution,disk-danger}-fill plus --progress-track. Each
  mode tunes the shade step so the bar reads on its track:

    Dark:    blue-400 / green-500 / yellow-500 / red-500
    Light:   blue-700 / green-800 / yellow-600 / red-700
    HC-light: blue-700 / green-800 / yellow-700 / red-700
    HC-dark:  blue-300 / green-400 / yellow-400 / red-400

  LumotiaProgress.svelte gains tone="transcribing", "disk",
  "disk-caution", "disk-danger" so callers map progress role to
  token explicitly.

Border / wireline / focus-ring discipline.

  Three distinct token families:
    --button-primary-border    structural component edge
    --button-primary-wire      complementary identity detail
    --focus-ring-color         keyboard interaction

  Documented as separate concerns in the tokens file.

Contrast check script.

  NEW: scripts/check-colour-contrast.mjs. Parses scales + tokens
  CSS, builds per-scope token tables for dark / light / HC-light /
  HC-dark, resolves var() chains and color-mix() expressions, then
  verifies twelve load-bearing component pairs against WCAG 2.2
  minima (4.5:1 text, 3:1 UI). Exit code 1 on failure.

  Current state: 0 failures across 4 modes.

  Two pairs reported as "warn" rather than "fail": caution progress
  on cream + caution notice border on cream. The yellow source colour
  cannot clear 3:1 on a near-white surface without losing its
  identity. Role recognition is carried by left-bar + icon + label,
  not by surface contrast.

Verified.

  - node scripts/check-colour-contrast.mjs: 0 failures, 4 modes, 12
    load-bearing pairs + 2 known-limitation warns.
  - npm run check: 0 errors, 0 warnings across 5707 files.

Phase 5c (Dictation layout migration) is the natural next focused
sitting. This commit gives Phase 5c the systematic colour grammar to
build on, and the contrast check gates future palette regressions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 16:00:17 +01:00
2c6f5ca230 v0.3 Phase 4j: colour grammar correction — record red, brand orange separate, wirelines bumped
Major correction per round-8 redirect.

Problem.

  - Brown/copper --color-accent #C97845/#9D5F32 was dragging the UI
    back into the warm-brutalist palette and competing with semantic
    yellow.
  - Record button about to become blue (Lumotia primary). Wrong —
    record is universally red across products and OSes.
  - Brand orange conflated with primary action. Orange should be
    brand mark only.

Solution.

  Source tokens — identity-only, never used directly in components:
    --source-red    #FF0700
    --source-yellow #FFCD00
    --source-green  #00FF56
    --source-blue   #000AFF
    --source-orange-brand #F0620A
    --{role}-complement-source for the wireline layer

  Component tokens — what components subscribe to. Hand-tuned hex
  values verified at WCAG AA on the foreground each button pairs with.
  Tonal scales (red-50..red-950 etc.) reserved for a focused future
  commit; component names stay stable through that upgrade:

    --button-record-bg     #DC2626  (red)
    --button-record-fg     #FFFFFF
    --button-record-border #B91C1C
    --button-record-wire   #00D8E0  (cyan, red's complement)

    --button-primary-bg    #2563EB  (blue)
    --button-primary-fg    #FFFFFF
    --button-primary-wire  #F6E600  (yellow, blue's complement)

    --button-danger-bg     same as record (red, fg white, cyan wire)

    --button-success-bg    #15803D dark / #166534 light  (green)
    --button-success-wire  #E600A0  (magenta, green's complement)

    --button-caution-bg    #FACC15  (yellow, fg #1A1500 near-black)
    --button-caution-wire  #1850D8  (blue, yellow's complement)

    --brand-accent          #F0620A (orange, LOGO ONLY)
    --brand-wire            #0A98F0 (cyan-blue, orange's complement)

  --color-accent repointed:
    quietware dark:   #4A7BFF  (was #C97845 copper)
    quietware light:  #1D4ED8  (was #9D5F32 copper)
    HC:               #005FCC  (existing, unchanged)
    v0.2 fallback:    var(--color-accent) preserved → v0.2 stays amber.

  New LumotiaButton variant: "record". Used by DictationPage's
  record control. Existing v0.2 record button class swapped from
  bg-accent (amber) to bg-[var(--button-record-bg)] (red). v0.2
  fallback at :root maps --button-record-bg to var(--color-danger)
  so non-quietware surface keeps its red-when-recording / amber-when-
  idle behaviour.

Wirelines (renamed from counterlines).

    --wire-width 1px / --wire-width-active 2px / --wire-width-focus 2px
    --wire-opacity-dark 0.75 (was 0.32; bumped per round-8 spec)
    --wire-opacity-light 0.6 (was 0.22)
    --wire-opacity-active 0.9
    --wire-opacity-focus 1
    --wire-opacity is a mode-aware resolver (-dark dark / -light light)
    --wire-style solid (dotted reserved for design-preview / drag-drop)

  HC contract: --wire-width 0, --wire-width-focus 2px kept.
  --focus-ring-color #005FCC (strong blue), not a decorative complement.

  Legacy --counterline-* tokens kept as aliases pointing at the new
  --wire-* set so Phase 4h/4i opt-in code still works.

Design-system-v2 preview now shows the new record variant alongside
primary so both red and blue button identities are visible.

Verified.

  - npm run check: 0 errors, 0 warnings across 5707 files.

Phase 5c (Dictation layout migration) still queued for the next
focused sitting. This commit gives Phase 5c the correct grammar to
build on.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 15:39:21 +01:00
001d8fe83d v0.3 Phase 4i: counterlines as interaction-affordance identity
Round-7 redirect (Option D): move counterlines from notices (where
they're invisible) to interactive controls (where they add identity).

Three-level model:

  Level 0  no counterline   panels, notices (default), content, disabled
  Level 1  quiet            controls, chips, active nav
                            1 px, 48% opacity dark / 34% light
  Level 2  focus / strong   keyboard focus, recording state
                            2 px, 85% opacity

Notices retire from default counterline rendering. Notice already
carries enough semantic language: bar + icon + border + bg + label.
A complementary inset on top was adding nothing. Notice can opt in
via <LumotiaNotice counterline ... /> when it deliberately mimics
control identity.

Token deltas vs Phase 4h.

  --counterline-width: 1px               unchanged
  --counterline-width-focus: 2px         new (Level-2 width)
  --counterline-opacity-dark: 0.48       was 0.32 (raised so Level-1
                                          actually reads on controls)
  --counterline-opacity-light: 0.34      was 0.22
  --counterline-opacity-focus: 0.85      new
  --role-brand-counterline: #3A6BFF      new (blue counter for the
                                          orange brand accent so
                                          primary buttons get an
                                          identity edge like the
                                          other roles)
  --button-{role}-counterline            new (per-role component tokens
                                          subscribing to role-counterline
                                          via color-mix)
  --focus-ring-color                     new (defaults to brand accent;
                                          HC overrides to #005FCC)

LumotiaButton applies counterlines to primary + destructive variants
only. Secondary + tertiary stay clean. All variants get a Level-2
focus-visible ring at --focus-ring-color * opacity-focus, with the
existing ring-offset-2 ring-offset-bg pattern.

LumotiaNotice gains a `counterline` boolean prop, default false. When
set, the previous Phase 4h inset shadow re-applies.

HC contract: counterline-width 0 + all -counterline tokens transparent.
Focus width stays 2 px because the HC focus ring IS the tactile
detail in that mode. focus-ring-color forces to #005FCC.

Honest evaluation of the visible result.

  Notices: visibly cleaner without the default inset shadow. Reads
  with more confidence. Good change.

  Buttons: counterline applied at 1 px / 48% dark / 34% light is
  perceptible at standard viewing but screenshot-zoom subtle. Focus
  state implemented but not visible in static screenshots; requires
  manual tab-test in the dev server.

  Recommend keeping the architecture even if the visual is restrained,
  because the focus-state work is genuinely valuable accessibility
  scaffolding regardless of how the Level-1 reads.

Verified.

  - npm run check: 0 errors, 0 warnings across 5707 files.

Phase 5c (Dictation layout migration) still queued for a focused
fresh sitting. This commit does not block it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 15:07:26 +01:00
74bcc293bb v0.3 Phase 4h: counterlines test on LumotiaNotice
Test commit for Jake's round-6 spec. Subtle 1-px inset shadow in a
softened complementary hue, applied to LumotiaNotice only. Other
test surfaces (Button.destructive, status pills, record ring, active
nav) reserved for after evaluation.

Tokens (quietware scope only, v0.2 surface unchanged):

  --counterline-width: 1px

  Raw complementary hues per Jake's table:
    --role-info-counterline    var(--color-accent)  /* copper for blue */
    --role-danger-counterline  #6EA8FF              /* soft blue for red */
    --role-success-counterline #B891FF              /* soft violet for green */
    --role-caution-counterline #3A6BFF              /* soft blue for yellow */

  Tinted per-mode via color-mix:
    Dark mode:   32% opacity (slightly stronger against dark surface)
    Light mode:  22% opacity (whisper-quiet against cream)
    HC mode:     all transparent, --counterline-width: 0

  Per-usage notice tokens emitted:
    --notice-{role}-counterline

LumotiaNotice applies via Tailwind arbitrary value:

  shadow-[inset_0_0_0_var(--counterline-width,0)_var(--notice-{tone}-counterline,transparent)]

HC contract zeroes both the width and the colour token so the 2-px
HC border carries the tactile detail instead.

Honest evaluation of the visible result.

  At 1px and 22%/32% opacity the counterline is implemented
  correctly but reads as whisper-quiet to the point of being almost
  invisible at standard viewing zoom. Doesn't look noisy (the risk
  Jake flagged), but also doesn't add perceptible tactility.

  Pending Jake's call:
    (a) raise opacity to ~45% dark / ~35% light for visibility,
    (b) keep at current opacity for the quietness,
    (c) revert and proceed Phase 5c.

  Phase 5c proceeds either way; this commit does NOT block the
  layout migration.

Verified.

  - npm run check: 0 errors, 0 warnings across 5707 files.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 14:50:55 +01:00
2f11f493c5 v0.3 Phase 4g: four-tier semantic tokens + notice usage layer
Round-5 feedback flagged the muddy result of forcing one --color-caution
to be both bright yellow (signal) and accessible text (ochre). The
single-token-per-role model collapsed the visible identity. Caution
notices ended up reading as brown/khaki surfaces because color-mix(
in oklab, var(--color-caution) 8%, transparent) over cream produced
muddy results whatever the source hex.

New architecture: four-tier per-role tokens, hand-tuned -bg surfaces,
plus usage-specific notice tokens on top.

Tier model — each semantic role publishes four tokens:

  signal  Brand-true colour. Left bars, large icons, dots, focus rings.
          Looks like the role at a glance.
  ink     Accessible text variant. Used ONLY when text itself must
          carry the role colour. WCAG AA 4.5:1 on its surface.
  border  Middle value. Visible chip/notice outline; not text-safe.
  bg      Hand-tuned pale tint surface. NOT a color-mix derivation.

Example, light-mode caution:
  --color-caution-signal #FFCD00  (bright yellow)
  --color-caution-ink    #7A5D00  (ochre, for small text only)
  --color-caution-border #D9A900  (mid gold)
  --color-caution-bg     #FFF7D6  (clean pale yellow tint)

--color-{role} retained as a backward-compat alias pointing at -signal.
v0.2 callers keep working; new code reaches for the specific tier.

Usage layer — components subscribe to usage-specific tokens, not
role-tier tokens directly:

  --notice-{role}-bar     left bar, signal-tier
  --notice-{role}-icon    signal in dark, ink in light, signal in HC
  --notice-{role}-border  outer border colour
  --notice-{role}-bg      hand-tuned pale surface

LumotiaNotice reads these via Tailwind arbitrary-value classes
(bg-[var(--notice-info-bg)] etc). v0.2 fallback values defined at
:root (outside quietware blocks) using color-mix from v0.2 --color-
{role} tokens so the Notice keeps rendering sensibly when quietware
is off.

HC contract — every -bg token forces to transparent. HC notices
render text + icon + 2-px border + left bar, no body tint. Brand
atmosphere steps fully aside.

Per Jake's round-5 spec: yellow stays yellow as the visible signal,
ochre only appears as small-text ink, and brown/khaki never
represents the caution role's primary visual identity again. Same
discipline applies to red/blue/green — each role has a clean
hand-tuned -bg pale tint per theme.

Verified — visible result.

  Light caution notice: bright #FFCD00 bar + signal icon + ink-darkened
  small icon + pale #FFF7D6 surface + #D9A900 border. Clean,
  semantically clear, no mud.

  Dark caution notice: bright #FFCD00 bar + signal icon + dark warm
  #29210A surface + bright yellow border. Reads as yellow at a glance.

  HC modes: no body tint, strong bordered notices, semantic colours
  preserved as primary identifier alongside icon + label.

  npm run check: 0 errors, 0 warnings across 5707 files.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 14:27:46 +01:00
2fcb5aff78 v0.3 Phase 4f/5a/5b: token architecture + skeleton + browser-preview reclass
Three small phases land together for Jake's round-4 feedback. Each is
focused and reviewable. Larger Dictation/Settings/Tasks/History page
migrations are deferred to focused future sittings.

Phase 4f — semantic source / derived token architecture.

  Added --semantic-{red,blue,green,yellow}-source raw-palette tokens.
  These encode the role's hue identity from Jake's color.adobe.com
  palette (#FF0700 / #FFCD00 / #00FF56 / #000AFF) and stay constant
  across all themes. The existing --color-{danger,caution,success,info}
  tokens are now documented as theme-tuned derivations meeting WCAG
  AA in context. Source tokens make the brand-to-runtime relationship
  traceable in code.

  Added --color-{role}-bg subtle-fill tokens derived via
  color-mix(in oklab, var(--color-{role}) 8%, transparent). Used by
  Notice backgrounds, hover tints and focus halos. HC mode forces
  -bg tokens to transparent so HC notices read as text + icon +
  2-px border + left bar with no body tint.

Phase 5a — page skeleton primitive + slim notice variant.

  NEW src/lib/ui/LumotiaPageSkeleton.svelte. Six-zone layout:
    header (optional)
    notice (optional, slim ambient state)
    primary work surface (required, primaryBleed for full-bleed)
    right rail (optional, lg-screen drawer)
    action bar (optional, bottom)
    metadata (optional, mono micro-footer)
  Every zone except primary is opt-in. Foundation for the
  page-skeleton sweep without forcing any page migration yet.

  LumotiaNotice gained a slim prop. When true: padding collapses
  (px-3 py-2 vs px-4 py-3), icon shrinks (14 vs 16), title block is
  suppressed. For ambient page-level notices like browser-preview.

Phase 5b — browser-preview reclassification.

  src/lib/pages/DictationPage.svelte: the browser-preview state used
  to render as a red error block. That is an environment limitation,
  not a failed action. Reclassified as a slim info notice with
  friendlier copy:

    "You're in a browser preview. Local transcription only works in
     the Lumotia desktop app."

  Other error states (transcription failed, needs review) still
  render through the original danger-tinted block with the
  technical-details affordance preserved. Only the browser-preview
  path branches into LumotiaNotice tone="info" slim.

The larger Dictation page restructure (header recomposition,
Template/Extract Tasks demotion to bottom action bar, empty-state
typography) is reserved for a focused Phase 5c sitting since
DictationPage.svelte is 1 262 LOC of state-heavy code.

Verified.

  - npm run check: 0 errors, 0 warnings across 5707 files.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 14:12:33 +01:00
dab9c7b5a6 v0.3 Phase 4d/4e: palette revision + HC rendering contract
Round-4 feedback (2026-05-15) pulled the system away from the
color.adobe.com primaries toward muted-Material values, separated
brand accent from semantic caution, and reframed high-contrast as a
behavioural rendering contract rather than a palette override.

Two phases land together because the palette revision and the HC
contract are inherently linked — HC mode needs both palette overrides
AND behavioural-token overrides to deliver "different rendering
contract" semantics.

Phase 4d palette revision.

  Dark mode (was wine-aubergine #2A1620, now brown-charcoal #12100E):
    --color-bg            #12100E
    --color-bg-elevated   #1A1713
    --color-bg-card       #211D18
    --color-bg-input      #181510
    --color-sidebar       #0F0E0C
    --color-border        #4A4035
    --color-border-subtle #2C261F

  Brand accent (new — was unset, fell through to v0.2 amber that
  competed with semantic yellow):
    Dark:  --color-accent #C97845 (copper)
    Light: --color-accent #9D5F32 (deeper copper)

  Semantic colours (muted-Material, both modes):
    Dark:  danger #FF8A8A  caution #F2C94C  success #79D59B  info #8AB4F8
    Light: danger #B3261E  caution #7A5D00  success #1B6B3A  info #2457A6

  Light mode work surface (slight paper tone, not pure white):
    --color-bg-card #FFFDF8 (was #FFFFFF)
    --color-bg-elevated #F6F1EA

  Caution fill-only-on-cream rule retires. Ochre #7A5D00 passes AA
  as foreground text on cream under the muted palette, so the single-
  token-per-role convention applies across all four semantic colours
  in both modes.

  LumotiaNotice opacity rebalance:
    Background tint  10% -> 8%
    Outer border     neutral subtle -> role at 40%
    Icon             --color-text -> role colour
    Left bar         role at 100% (unchanged)
    Title / body     --color-text (unchanged)

Phase 4e HC rendering contract.

  Behavioural tokens published alongside palette:
    --grain-opacity            0.06 dark / 0.07 light / 0 in HC
    --shadow-strength          1 default / 0 in HC
    --border-width-control     1px default / 2px in HC
    --focus-ring-width         2px default / 3px in HC
    --panel-radius             8px (reserved for future tightening)

  --quietware-texture-opacity retained as a legacy alias pointing at
  --grain-opacity so Phase 4c slider keeps working through the rename.

  HC palette: pure-black or pure-white base, the other for borders,
  single strong-focus blue #005FCC replaces accent. Brand atmosphere
  steps aside. Selector splits via :not([data-theme="light"]) so
  HC-light and HC-dark variants diverge cleanly.

Verified.

  - npm run check: 0 errors, 0 warnings across 5706 files.
  - Plan doc updated with full before/after tables, behavioural-token
    contract table, and Phase 4c / 4d / 4e log sections.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 13:50:11 +01:00
4dca802f0b v0.3 Phase 4c: HC toggle + texture-intensity slider + grain overlay
Three additions land together so the slider is meaningful from day
one (instead of recording a preference that nothing consumes yet).

Static grain overlay.

  - src/design-system/v0.3-quietware-tokens.css adds a fixed-position
    body::after element that ships an SVG feTurbulence noise tile
    repeated across the viewport. Opacity reads from
    --quietware-texture-opacity. mix-blend-mode: overlay produces the
    soft notebook-paper feel without obscuring content.
  - pointer-events: none so clicks pass through. Active only under
    html[data-design="quietware"]. High-contrast forces opacity to 0
    via the existing HC palette block.

QuietwareAccessibilityControls component.

  - NEW: src/lib/components/QuietwareAccessibilityControls.svelte.
    Two controls, both quietware-only:
      1. High-contrast toggle wires html[data-contrast="high"].
         Overrides the OS prefers-contrast: more query when explicitly
         on. Built on LumotiaToggle so it inherits the accessible
         label + description pattern.
      2. Texture-intensity slider, range 0.05 to 0.08, step 0.005,
         default 0.06. Sets --quietware-texture-opacity inline on
         <html>, overriding the per-mode default in the tokens CSS.
         Disabled while high-contrast is on. Reset button restores
         0.06.
  - Persistence: localStorage keys
      lumotia:quietware:high-contrast
      lumotia:quietware:texture-opacity
    so choices survive dev rebuilds and full restarts. Full
    integration with the central Preferences store is a follow-up;
    localStorage keeps Phase 4c contained.

SettingsPage Accessibility section.

  - Imports the new QuietwareAccessibilityControls component.
  - Renders {#if isQuietware} <QuietwareAccessibilityControls />
    {/if} immediately after the existing AccessibilityControls block.
  - Search filter copy extended to cover the new control vocabulary.

Verified.

  - npm run check: 0 errors, 0 warnings across 5706 files.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 13:43:58 +01:00
091780086b v0.3 Phase 4a: Settings tab shell
Discovers that v0.2 SettingsPage.svelte was already structured as
eight numbered sections aligning almost 1:1 with the v0.3 plan. The
cheapest path to "one section visible at a time" is therefore a
tab-shell overlay rather than a file split. Behaviour stays identical
to v0.2 when quietware is off; with quietware on, only the active
tab's section renders.

Changes.

  - NEW: src/lib/ui/LumotiaSettingsTabs.svelte. Tab list following
    the WAI-ARIA "tabs (automatic activation)" pattern. Arrow / Home /
    End keyboard navigation. Active tab uses the brand left-bar
    accent (border-l-caution) — same grammar as the LumotiaNotice
    refactor from Phase 3.

  - MODIFIED: src/lib/pages/SettingsPage.svelte. Added an isQuietware
    reactive flag, a MutationObserver watching <html data-design>,
    an activeTab state, and eight {#if !isQuietware || activeTab ===
    'X'} wrappers around the existing top-level SettingsGroup
    sections. The settings tree is unchanged; only its top-level
    rendering gate changed.

  - v0.2 fallback: when data-design="quietware" is absent the
    tablist does not render and all eight sections stack as before.
    The search filter spans every section in v0.2 mode. Smallest-
    possible behavioural change for "one section at a time".

Tab IDs in this commit map 1:1 to existing v0.2 section names
(start-here / transcription / models / tasks / accessibility /
privacy / advanced / help). Phase 4b will restructure to the plan's
canonical names (carving Output from Advanced and Vocabulary from
Transcription).

Phases 4b and 4c are logged as pending in the plan doc:
  4b. Restructure to canonical tab names (Output, Vocabulary).
  4c. Texture-opacity slider + high-contrast toggle in Accessibility.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 13:22:13 +01:00
db9c50c548 v0.3 Phase 3: status grammar — LumotiaNotice left-bar refactor
Phase 3 audit found that both LumotiaStatusPill and LumotiaNotice
already shipped in v0.2 Phase 5. Phase 3 reduced to an audit-and-adapt
pass.

LumotiaStatusPill ($lib/components/StatusPill.svelte) is already
correct for quietware. Pattern: neutral pill background + neutral
label text + role colour confined to a 6x6 px dot. Colour is
supplementary, label is always perceivable. Works unchanged across
all three quietware modes. No changes shipped.

LumotiaNotice ($lib/ui/LumotiaNotice.svelte) refactored to the
left-bar accent pattern. Previously the role colour rendered on the
icon outline and on the entire surround border at 30% opacity; in
quietware light mode that left the bright #FFCD00 caution colour
faded against cream paper. New pattern:

  - 4-px solid LEFT border in the tone colour, 100% opacity.
  - Soft tone-tinted background (10% opacity) for ambient cue.
  - Subtle neutral outer border on the other three sides.
  - Icon, title and body text all use --color-text.

Visible signal lives on the large bar (works at any contrast level);
foreground text uses the always-legible neutral. Matches Material
Design "banner with leading accent" and IBM Carbon "inline
notification" guidance. ARIA semantics (role="alert" for danger,
role="status" for the rest) preserved.

Design-system-v2 preview route already imports both primitives. The
updated Notice renders correctly with the existing preview content;
no additional wiring required.

Caution remains a fill-only convention on cream by design. Any
darkened yellow reads as olive ("looks like poop", per Jake), so the
fill-only rule stays in force and this pattern delivers it cleanly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 13:03:00 +01:00
a9972f76bb v0.3 Phase 2: build flag wiring
Wires VITE_LUMOTIA_QUIETWARE=1 to set <html data-design="quietware">
via a $effect in src/routes/+layout.svelte. Without the flag the
runtime app behaves exactly as v0.2; with the flag the v0.3 token
overrides in src/design-system/v0.3-quietware-tokens.css activate.

Hot-reload safety: if the env var is unset between dev rebuilds, the
attribute is cleared so devs do not see a stuck quietware surface.

Activation paths:

  VITE_LUMOTIA_QUIETWARE=1 npm run dev          (development)
  VITE_LUMOTIA_QUIETWARE=1 npm run build        (production)
  Or manually via dev tools: <html data-design="quietware">

Combine with data-theme="light" (existing v0.2 theme wiring) and
data-contrast="high" (existing v0.2 contrast wiring) to reach the
light and high-contrast quietware modes.

Smallest possible PR. No new dependencies. No bundle-size impact in
the off path. No component changes. Plan doc updated to mark Phase 2
as landed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 12:53:56 +01:00
7075c205fc v0.3 Phase 1: palette amendment to color.adobe.com primaries
Third palette iteration. Source: Jake's color.adobe.com primaries
attached to the Phase 1 review reply 2026-05-15:

    #FF0700  red     -> --color-danger
    #000AFF  blue    -> --color-info
    #00FF56  green   -> --color-success
    #FFCD00  yellow  -> --color-caution

Each primary is used literally where it clears WCAG AA on the
relevant background. Where it does not, a text-safe sibling at the
same hue and saturation is derived.

  LIGHT MODE on cream paper
    --info     #000AFF  Jake literal       7.96 AAA
    --danger   #E60600  sibling            4.51 AA
    --success  #00852D  sibling            4.51 AA
    --caution  #FFCD00  Jake literal       1.42 (fill-only by convention)

  DARK MODE on lifted Coffee Bean #2A1620
    --info     #7076FF  lifted from blue   4.64 AA
    --danger   #FF2A24  lifted from red    4.54 AA
    --success  #00FF56  Jake literal       12.51 AAA
    --caution  #FFCD00  Jake literal       11.33 AAA

  HIGH CONTRAST on black, S=80% L=70%
    --info     #757AF0  5.80 AA
    --danger   #F07975  7.70 AAA
    --success  #75F09F  14.72 AAA
    --caution  #F0D875  14.78 AAA

Caution remains a fill-only convention on cream. Any darkened yellow
reads as olive or mustard, which Jake refused at the round-2 stage
(see capture 2026-05-15-re-lumotia-v03-renders-revised-palette-).

No component changes. No behavioural changes. Phase 1 still inert
without html[data-design="quietware"]. Supersedes the cobalt-pegged
square palette in commit f718ade. Geometry geometry argument retired;
canonical brand primaries take its place.

Plan doc updated with the new palette tables and the round-3
refinement reference. Phase 1 log notes the three-iteration journey.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 12:51:38 +01:00
f718aded16 v0.3 Phase 1: Tactile Quietware tokens
Foundation for the v0.3 Tactile Quietware release. Tokens only. No
component refactors, no layout changes, no behavioural shifts. The new
palette and typography activate only when html[data-design="quietware"]
is set; the runtime v0.2 surface is unaffected without the attribute.

What landed.

  - Three-mode palette (light, dark, high-contrast) at
    src/design-system/v0.3-quietware-tokens.css. Strict 90deg square
    colour harmony pegged at cobalt blue #0047AB. Hues: 215 / 305 / 35
    / 125. Saturation locked at 100%. Lightness adjusted per role for
    WCAG AA 4.5:1 on the relevant background; computed values
    documented in the plan doc.

  - V4 font stack self-hosted as WOFF2:
        Work Sans (variable, roman + italic) for body, UI, controls.
        Young Serif for brand moments only.
        JetBrains Mono stays via existing src/fonts/jetbrains-mono.woff2.

  - Import wired in src/app.css directly after the tailwind import.
    The new tokens are inert until data-design="quietware" is set on
    <html>.

  - Reduced-motion override scoped to quietware so prefers-reduced-motion
    actually bites inside the new design system from day one.

  - Plan doc at docs/release/v0.3-tactile-quietware.md with the full
    seven-phase plan (Phase 1 logged), four high-priority persona test
    gates (Pawel, Simone, Chris, Ron), and the Phase 0 gov.uk DfE
    accessibility tools checklist.

Activation paths.

  - Manual now: dev tools, set <html data-design="quietware">.
  - Phase 2 will wire VITE_LUMOTIA_QUIETWARE=1 through +layout.svelte.

Verified.

  - npm run check produced 26 errors but all 26 are pre-existing in
    files this PR does not touch (LumotiaTooltip.svelte missing
    bits-ui import; tests/e2e/smoke.spec.ts missing playwright types).
    Tracked separately, not blocking v0.3 Phase 1.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 12:15:07 +01:00
f03f8a01b0 v0.2 Phase 8: full release gate — all checks green
cargo fmt --check                                         ✓
  cargo clippy --workspace --all-targets -- -D warnings     ✓
  cargo test --workspace                                    ✓
  cargo nextest run --workspace                             ✓ 435/435
  npm run check                                             ✓ 0/0/5704 files
  npm test                                                  ✓ 13/13 (2 files)
  npm run test:browser                                      ✓ 3/3 in Chromium
  npm run test:e2e                                          ✓ 16/16 × 2 viewports
  npm run analyze                                           ✓ reports/bundle-stats.html (1.7 MB)
  scripts/dogfood-rebrand-drill.sh                          ✓ 8/8 (sandbox)
  npm run guard:no-skeleton                                 ✓ clean

Two small Phase 8 corrections landed alongside the gate:

vite.config.js: the jsdom suite was picking up
`src/lib/ui/*.browser.test.ts`, which only works under the
@vitest/browser-playwright provider. Added the browser-suffix glob to
the jsdom suite's exclude list so the two runners stop double-running
the same files.

playwright.config.ts: bumped the global `expect.timeout` to 15 s. The
cold first-compile of the Vite SPA tree was exceeding Playwright's
default 5 s `toBeVisible` timeout on the 900x700 project on dogfood
runs. The 1440x900 project (which runs second after a warm cache)
never hit it.

Phase 8 closes Phase-7 page migrations. Branch is ready for the
finishing-a-development-branch handoff.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 09:07:10 +01:00
ba851680ce v0.2 Phase 7.8 / 7.9 / 7.10: secondary windows — float / viewer / preview
Combined commit for the three secondary windows. Each +layout@.svelte
was already migrated in Phase 3 KI-05 (the legacy theme-sync $effect
was deleted). The +page.svelte content for each window is explicitly
bespoke per docs/release/v0.2-frontend-overhaul.md §6.3:

  /float    — Lumotia-To-do panel: list pills, drag-and-drop between
              lists, context menus, pin-on-top, custom titlebar drag
              region. No Card/EmptyState/Toggle wrappers apply.

  /viewer   — Transcript viewer with audio player, segment scrubbing,
              speaker labels. Bionic-reading action + per-region
              accessibility typography are load-bearing. No wrappers.

  /preview  — Wayland-hardened transcription preview overlay.
              WindowTypeHint::Utility, never steals focus, hidden
              from Alt+Tab. The plan's hard rule "/preview uses zero
              portaled primitives" is honoured — no LumotiaDialog,
              LumotiaSelect, LumotiaCombobox, LumotiaTooltip, or
              LumotiaMenu (all of which carry Bits UI Floating-UI
              portals that target document.body).

Phase 7 closes here. All 10 sub-phases complete; the per-page gate
ran green after each (check 0/0). Full Phase 8 gate fires next.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 09:02:41 +01:00
a9733544c0 v0.2 Phase 6: shell split — AppRuntime / AppChrome / AppOverlays
src/routes/+layout.svelte was 537 LOC of mixed runtime, chrome and
overlay concerns. Split into three single-purpose shells under
src/lib/shell/, with +layout.svelte reduced to ~28 LOC of pure
composition.

AppRuntime (no DOM beyond <svelte:window>):
  - Global hotkey dual backend (evdev / tauri-plugin-global-shortcut)
  - 120ms hotkey debounce (sacred behaviour §5 #2)
  - PREFERENCES_CHANGED_EVENT listener (sacred §5 #4)
  - KI-05 one-shot legacy-theme migration
  - Sidebar hotkeys: [ toggle, Ctrl+K, Ctrl+, (sacred §5 #10)
  - Wind-down tray listener
  - Meeting auto-capture poller
  - Global frontend error capture
  - Nudge bus + implementation intentions lifecycle
  - Font-size CSS var $effect
  - Window resize → sidebar auto-collapse
  - Onboarding/first-run check + update check + LLM status warm-up

AppChrome (the visual shell):
  - Titlebar (OS-aware via customChrome helper)
  - Sidebar (recording-state-aware — sacred §5 #1 stays in
    Sidebar.svelte verbatim)
  - Main slot
  - TaskSidebar conditional rail

AppOverlays (mounted-once globals):
  - ToastViewport
  - FocusTimer
  - MorningTriageModal
  - ResizeHandles (OS-gated)

src/lib/utils/customChrome.svelte.ts holds the single source of truth
for useCustomChrome, a module-level $state both AppChrome and
AppOverlays subscribe to. Each only ever sees one loadOsInfo() call
between them.

Secondary windows still escape via their own +layout@.svelte; the
defensive isSecondaryWindow check in +layout.svelte stays so a
direct /float, /viewer, /preview navigation through the root layout
also drops the chrome.

Phase 6 per-page gate green: npm run check (0/0/5704 files),
npm test, npm run test:browser (3/3), npm run test:e2e (16/16).
No regressions in the Phase 1 smoke baseline.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 08:51:55 +01:00
c60f0aa5a5 v0.2 Phase 5: 11 primitives + gated design-system-v2 preview
Custom-styled primitives (no headless dep):
  LumotiaButton       — primary/secondary/tertiary/destructive × sm/md/lg
  LumotiaIconButton   — square icon-only; ghost/filled/destructive
  LumotiaNotice       — info/caution/danger/success inline notice
  LumotiaProgress     — native <progress> + token theming
  LumotiaField        — plain + Formsnap modes share the same markup

Bits UI 2.18.1 wrappers (warm-brutalist styling):
  LumotiaSelect       — single-select, options=[]
  LumotiaCombobox     — searchable; one-way inputValue + oninput
  LumotiaDialog       — controlled open; closable + footer snippet
  LumotiaTabs         — orchestrates List/Trigger/Content from a tabs array
  LumotiaTooltip      — wraps Provider + Root + Trigger + Content
  LumotiaMenu         — DropdownMenu items=[] with destructive variant

design-system-v2 preview route:
  src/routes/design-system-v2/+page.ts gates with VITE_LUMOTIA_DESIGN_SYSTEM_V2=1.
  Without the flag the load() throws 404 — route-level gate, not nav-
  hidden. Run via VITE_LUMOTIA_DESIGN_SYSTEM_V2=1 npm run dev:frontend
  to see the showcase.

Browser-mode component test:
  src/lib/ui/LumotiaButton.browser.test.ts. Covers render, click, and
  disabled-blocks-click. Validates that vitest-browser-svelte + the
  @vitest/browser-playwright provider land Phase 1's tooling
  contract end-to-end. 3/3 passing in Chromium.

Type fix: LumotiaIconButton and LumotiaMenu accept icon: any so
lucide-svelte's legacy SvelteComponentTyped shape composes with our
Svelte 5 wrappers without forcing a // @ts-nocheck escape hatch on
every call site. Tightens to Component<…> once lucide-svelte ships
a Svelte 5 build.

Type fix: LumotiaCombobox honours Bits UI 2.x Combobox.Root's
one-way inputValue contract. The wrapper drops bind:inputValue
and exposes an oninput callback so caller-owned filter pipelines
(HistoryPage FTS5, ModelDownloader) can drive options upstream.

Phase 5 per-page gate green: npm run check (0/0/5700 files),
npm test, npm run test:browser (3/3 in Chromium),
npm run test:e2e (16/16), guard-no-skeleton clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 08:47:53 +01:00
8c9708a508 v0.2 Phase 4: wrapper alias layer (src/lib/ui/)
Six thin alias wrappers, same prop APIs as the underlying components.
Lets pages migrate imports from $lib/components/* to $lib/ui/* one
file at a time without touching markup, and gives Phase 5+ a place
to tighten grammar without churning every call site.

  LumotiaCard           → Card.svelte
  LumotiaStatusPill     → StatusPill.svelte
  LumotiaToggle         → Toggle.svelte (forwards bind:checked, bind:loading)
  LumotiaSettingsGroup  → SettingsGroup.svelte (typed Props for svelte-check)
  LumotiaEmptyState     → EmptyState.svelte
  LumotiaPostCaptureCard → PostCaptureCard.svelte

Per the plan, the underlying components in src/lib/components/ are
untouched. They get retired during the per-page migrations in Phase 7
once no consumer remains.

LumotiaSettingsGroup mirrors the underlying Props interface explicitly
because Svelte 5's spread-into-typed-component caught a real missing-
`title` error during svelte-check. The mirrored interface keeps call
sites type-safe when importing via $lib/ui/.

Phase 4 per-phase gate green: npm run check (0/0/4135 files),
npm test (all green), npm run test:e2e (16/16), npm run
guard:no-skeleton (clean).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 08:38:23 +01:00
66e25aa778 v0.2 Phase 3: additive semantic tokens + KI-05 resolution
Additive token grammar (no renames, no replacements):

- --color-caution (dark #e8be4a, light #a08a1f) becomes the canonical
  name for tuned-amber notice surfaces in the new wrapper grammar
- --color-warning is kept as a CSS var() alias of --color-caution so
  every existing text-warning / bg-warning call site stays valid
- --color-info (dark #7a9ec0, light #3d6a8a) is the soft blue-grey
  signal for the new LumotiaNotice info variant
- --color-accent-environment (dark #8fae9a, light #4a7058) is an
  optional sage/moss support token for empty-state illustrations
  and environment-neutral status dots. NOT a brand swap — amber/
  copper --color-accent stays primary

Mirrored in src/design-system/colors_and_type.css (the buildless
preview pages bypass Tailwind so the duplication is intentional).

KI-05 resolved in the same commit, per the plan:

- src/lib/types/app.ts: drop `theme` from SettingsState
- src/lib/stores/page.svelte.ts: drop `theme: "Dark"` from defaults
- src/routes/+layout.svelte: drop the migration $effect, add a
  one-shot migrateLegacyTheme() on mount that copies any historical
  lumotia_settings.theme into preferences.theme and strips the
  legacy field. Idempotent — subsequent loads short-circuit
- src/routes/{float,viewer,preview}/+layout@.svelte: drop the same
  $effect; secondary windows inherit theme via PREFERENCES_CHANGED_EVENT
- src/lib/pages/SettingsPage.svelte: both SegmentedButton bindings
  (quick-settings row at :1272, Appearance group at :2606) now use
  Svelte 5 function bindings ({ get, set }) backed by prefs.theme
  and updatePreferences. No SegmentedButton API change

Phase 3 per-page gate green: npm run check (0/0/4129 files),
npm test (13/13), npm run test:e2e (16/16). No regressions in
the Phase 1 smoke baseline.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 08:35:54 +01:00
100e04fa70 v0.2 Phase 0+1: planning doc + tooling baseline
Phase 0 — docs/release/v0.2-frontend-overhaul.md as single source of
truth for the v0.2 frontend coherence pass. Records hard rules,
tooling pins, sacred-behaviour contract list, wrapper catalogue,
per-page migration order, verification matrix, KI-05 plan, and the
explicit "DO NOT add Skeleton" line.

Phase 1 — tooling baseline. All exact-pinned per the plan:

- @playwright/test@1.60.0 + playwright@1.60.0 + @axe-core/playwright@4.11.3
- rollup-plugin-visualizer@7.0.1 (wired behind ANALYZE=1)
- @vitest/browser@4.1.6 + @vitest/browser-playwright@4.1.6 (provider)
- vitest-browser-svelte@2.1.1 (runes-aware Svelte 5 bridge)
- cargo-nextest installed globally

New configs: playwright.config.ts (frontend-only, dev:frontend webServer,
900x700 + 1440x900 projects, visual baselines deferred), vitest.browser.config.js
(separate from jsdom suite). New scripts: test:e2e, test:e2e:ui,
test:browser, analyze, test:rust:fast, guard:no-skeleton.

guard-no-skeleton.mjs walks package.json + package-lock + src/ for any
@skeletonlabs reference and exits 1 if found — locks in the no-Skeleton
hard rule for any future agent.

Smoke baseline (tests/e2e/smoke.spec.ts): 16 tests passing across two
viewports — app loads without Tauri runtime, keyboard nav, axe scan
(color-contrast deferred to Phase 7 per docs/release/v0.1-contrast-audit.md),
light/dark theme cycle, all three sensory zones (cave/energy/reset).
10 screenshots emitted to test-results/ as non-failing artefacts.

Surfaced + fixed two browser-preview bugs while landing the baseline:

- src/lib/utils/osInfo.ts: FALLBACK_BROWSER_INFO was evaluated at SSR
  module-load (navigator undefined → os: 'unknown'), and the UA check
  ran before navigator.platform — so Playwright's Windows-UA Chromium
  on a Linux runner detected as Windows, useCustomChrome went true,
  Titlebar mounted and tripped Tauri-only APIs. Now lazy-built per
  call; platform is the primary signal, UA only a fallback.

- src/lib/components/Titlebar.svelte: defensive hasTauriRuntime() guard
  on every handler and the $effect. Titlebar should not crash if any
  future code path mounts it without Tauri.

.gitignore: reports/, .playwright/, test-results/, playwright-report/.

Per-phase gate green: npm run check (0/0), npm test (0/0), npm run
test:e2e (16/16), npm run guard:no-skeleton (clean).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 08:28:51 +01:00
3770815fbf agent: lumotia — v0.1 release-completion run
Some checks failed
check / cargo check (macos-latest) (push) Has been cancelled
check / cargo check (ubuntu-22.04) (push) Has been cancelled
check / cargo check (windows-latest) (push) Has been cancelled
check / svelte build + lint (push) Has been cancelled
Closes the code-side v0.1 ship gate. All quality gates green:
cargo fmt/clippy/test (~327 tests), npm check (0/0), vitest 13/13,
scripts/dogfood-rebrand-drill.sh 8/8.

Phase F — first-run onboarding promoted to v0.1
- FirstRunPage with skip-to-main + failure recovery + event recording
- Six onboarding commands (record/list/has-completed + lumotia_events)
- Storage migration v17 (onboarding_events + lumotia_events tables)

UI hardening (in-scope items from v0.1-ui-hardening.md)
- StatusPill + PostCaptureCard components, 21st preview entry
- Sidebar recording-as-sacred-state (opacity + aria-disabled, reduced-motion)
- Settings 6-section regroup + Help section + Activation log + Privacy toggle
- Error-state copy sweep (DictationPage + SettingsPage, plain-language)
- Global :focus-visible rule, textarea outlines restored
- Ctrl+K / Ctrl+, / Escape bindings in +layout

LLM resilience
- rule_based_extract_tasks (regex-free imperative-verb extractor) +
  extract_tasks_with_fallback wrapper — task extraction never returns zero
- tokio::time::timeout(120s) wraps cleanup/tags/tasks commands

Release artefacts
- LICENSE (canonical AGPL-3.0), CHANGELOG (Keep-a-Changelog format)
- v0.1-release-notes, privacy-and-ai-use, install-warnings,
  tester-onboarding-kit, tester-acceptance-runbook, code-signing-setup,
  apple-silicon-rb08-runbook, virtual-audio-setup, v0.1-contrast-audit
- Workspace versioning + AGPL spdx; npm exact-pin (10 ranges removed)
- AppImage SHA-256 sidecar in build.yml
- README v0.1 section + Reporting-issues; canonical repo slug

Closure pass — items moved from human-required to code-complete
- KI-02 Linux idle inhibit: zbus 5 → org.freedesktop.login1.Manager.Inhibit
- KI-03 Windows sleep prevention: SetThreadExecutionState(ES_CONTINUOUS|...)
- acquire/release_idle_inhibit Tauri commands, wired in DictationPage
- Diagnostic-bundle frontend wire-up (Settings → Help button)
- WCAG-AA contrast fix via .btn-filled-text utility (no token changes)
- 8 destructive-action sites wrapped in plain-language confirm() guards
- KNOWN-ISSUES.md + v0.1-known-limitations.md updated (KI-02/03 fixed)

Scripts
- pre-tag-verify.sh, tag-day.sh, smoke-linux + driver
- parse-diagnostic-bundle.sh, parse-activation-log.py

Per-item audit trail: docs/release/v0.1-completion-status.md
Remaining: W-01…W-08 (signing certs, hardware probes, smoke matrix,
tester recruitment) — see docs/release/v0.1-known-limitations.md.
2026-05-15 06:59:08 +01:00
bf1b68275a agent: lumotia — Pass 1 v0.1 checklist refinements + Pass 2 v0.1 UI hardening boundary doc
Operationalises the ChatGPT review of the v0.1 release-doc set into two
related landings. Both bounded; no Garden Inbox work, no architecture
refactor, no full redesign.

PASS 1 — v0.1-checklist.md refinements
=======================================

Seven targeted edits to the existing checklist:

1. Cold setup vs warm activation split. Tester acceptance test was
   conflating model-download time (variable, network-dependent) with
   UX-controlled flow time. Two-phase pass:
     - Cold setup: install → onboarding → ready-to-record (no time bound)
     - Warm activation: model-ready → first recording within 3 minutes
   Steps 1-4 are cold; 5-10 are warm.

2. Migration-aware onboarding wording. "Skip-onboarding path for users
   who already have transcripts on disk" → "Migration-aware onboarding:
   existing users with valid data are not forced through first-run, but
   can launch the tutorial manually from Settings → Help."

3. UI acceptance section. New testable items between Documentation
   surface and Quality gates — turns "redo the UI" into measurable
   requirements:
     - Main capture action visible <1s on Home
     - Recording state not communicated by colour alone
     - 10-step flow completable at 900×700 + keyboard only
     - Destructive actions reversible or confirmed
     - Every async state has sidebar status chip feedback
     - Error states preserve raw transcript + plain-words next step
     - Settings Start Here / Privacy / Accessibility findable
     - Focus ring visible everywhere
     - prefers-reduced-motion respected
     - WCAG AA contrast spot-check both modes
     - Post-capture card surfaces (display-only; NOT Garden Inbox)

4. Supported platforms scope. New subsection before smoke-test matrix
   explicitly naming:
     - Primary (must work end-to-end): Linux Fedora + Ubuntu LTS
     - Best-effort (announced if smoke-tested): macOS Apple Silicon,
       Windows 11
     - Not announced unless smoke-tested: macOS Intel

5. P0/P1/P2 smoke-test severity replacing "any  blocks tag":
     - P0 — blocks tag (tester spine on a primary platform)
     - P1 — ships only with explicit known-limitation entry
     - P2 — does not block private beta (not-announced platform / v0.2
       feature)
   Pre-tag verification confirms no unresolved P0 or undocumented P1.

6. "Telemetry" → "local activation log". Re-worded the activation
   metrics capture mechanism. Word choice deliberate — privacy-conscious
   audience reacts to "telemetry" itself. Surface: Settings →
   Diagnostics → Activation log. Nothing sent automatically.

7. Support burden signal. New activation-metric subsection covering
   the AI-assisted-indie risk that every issue becomes a support call:
     - Self-service rate ≥ 70% (issues filed to bug tracker, not inbox)
     - Diagnostic bundle (logs + system info + crash dumps; skips
       transcript content + audio by default)
     - Top-3 setup failures documented after first 5 testers

PASS 2 — v0.1-ui-hardening.md
==============================

New strict-boundary doc at docs/release/v0.1-ui-hardening.md (262
lines). Anchored on the line:

  The v0.1 UI pass is not there to make Lumotia beautiful. It is there
  to make the first successful capture inevitable.

Step 0 (before any code change): walk the 20 existing
src/design-system/preview/ files and classify each item as
already-good / needs-v0.1-hardening / v0.2-polish. Don't rebuild what
works. Inventory table inline in the doc cross-references each preview
file to the in-scope items below.

IN SCOPE (10 items, each testable):
  1. Home capture clarity — big record button, status pill, last-capture
     preview, capped Now/Tasks at 1-3 visible
  2. Recording as sacred UI state — hide settings/history/advanced
     during capture; show only timer/pause/stop/cancel + live transcript
     + level meter
  3. Post-capture card — the v0.1 headline UI artefact. Display-only
     surface of raw + cleaned + tasks + microsteps + 4 actions
     (Save/Export/StartFirstMicroStep/OpenInHistory). Explicitly NOT
     Garden Inbox: no routing, no accept/edit/park/archive, no
     backlinks, no confidence scores
  4. First-run onboarding polish — single clear next action per step,
     pre-supplied prompt for test recording, graceful failure recovery,
     skip-to-main escape hatch (tracked as known-limitations follow-up)
  5. Settings sanity pass — 6 sections in order: Start Here /
     Transcription / Models / Tasks / Accessibility / Privacy / Advanced.
     Full 7-group progressive-disclosure regroup deferred to v0.2
  6. Error-state copy sweep — every error preserves raw transcript,
     explains in plain words, says next user action, no stack traces
     user-facing
  7. Keyboard flow — entire 10-step tester acceptance completable by
     keyboard only, focus ring visible, no hover-only controls
  8. Responsive at 900×700 + 1440×900 ONLY — ultrawide / mobile / split-
     screen deferred to v0.2 unless a tester reports them
  9. Accessibility practical checks (WCAG-style, not certification) —
     keyboard, focus, not-colour-alone, reduced motion, contrast spot-
     check, literal-words status labels, form-label association
  10. Status labels everywhere — new StatusPill component (no existing
     class found in survey); add to design-system/preview/components-
     status-pills.html. Pill states: Ready / Recording / Paused /
     Transcribing / Cleaning / Extracting tasks / Saved / Exported /
     Needs review / Failed safely

OUT OF SCOPE (the traps to refuse — each ships in v0.2 or later):
  - New visual identity (brand book v3 PDF is locked)
  - New navigation model
  - Garden Inbox (review cards, routing, accept/edit/park/archive,
    related notes, backlinks, P-P-T detection)
  - Suggested routing
  - Backlinks
  - Graph view
  - Canvas view
  - New animation system
  - Full SettingsPage 7-group redesign
  - Obsidian plugin
  - Cloud / provider UI

Plus a "Definition of done" with 8 specific completion criteria, and
cross-references to checklist + Garden roadmap + how-built + design-
system preview + locked brand book.

VERIFICATION
============
- cargo fmt --check: clean (no Rust touched)
- All four release docs cross-reference cleanly
- No new tests required (boundary docs, not code)
- v0.1 ship gate unchanged in shape, sharpened in detail
2026-05-14 22:12:21 +01:00
c5460a169c agent: lumotia — release-doc set + two pre-release audits (MCP + LLM failure)
Operationalises the ChatGPT/Jake roadmap-synthesis pass into four
release-boundary documents at docs/release/. Synthesis call:

  v0.1 = stable local capture product
  v0.2 = Garden Inbox / review cards
  v1.0 = PKM-complete + commercial track

Two factual audits ran first per Jake's explicit instruction — release
hardening only, no architecture refactors, no Garden Inbox work:

AUDIT 1 — MCP surface
=====================
Verdict: PASSES the v0.1 trust posture.
- Read-only by design (`//! No writes — Lumotia's Tauri app remains the only writer`)
- Stdio-only transport (newline-delimited JSON-RPC 2.0); no TCP/Unix
  listener, no bind, no network exposure
- Database opened via `lumotia_storage::init_readonly` — structurally
  enforced, not just convention
- 4 tools, all SELECT-only: list_transcripts, get_transcript,
  search_transcripts, list_tasks
- Zero matches for INSERT/UPDATE/DELETE/fs::write/fs::remove/
  create_dir/spawn_blocking in the crate
- Separate binary (`crates/mcp/src/main.rs`) — not part of the running
  Tauri app; user must explicitly launch and wire into client config
- Honest nuance flagged in known-limitations: a wired client gets read
  access to the entire transcript history + task list — no per-row
  permission boundary in v0.1

AUDIT 2 — LLM failure surface
=============================
Verdict: data-loss path PASSES; UX-wedge path PARTIAL (documented).
- post_process_segments (file + live pipeline): tracing::warn! on Err,
  segments stay at rule-based output. Raw transcript preserved.
- cleanup_transcript_text_cmd (DictationPage): frontend try/catch
  returns raw text unchanged on Err. Raw transcript preserved.
- extract_tasks_from_transcript_cmd (DictationPage): frontend falls
  back to rule-based extractTasks (regex + verb list) on Err.
- extract_content_tags_cmd (HistoryPage): per-row try/catch; toast on
  failure; transcript untouched.
- Hung llama.cpp: no tokio::time::timeout on the spawn_blocking call.
  Raw transcript preserved; rest of app functional; LLM status chip
  stays on "Cleaning up" until restart. Soft edge — documented in
  known-limitations as v0.2 hygiene candidate. Not implemented per
  "release hardening only" instruction.

THE FOUR DOCS
=============

docs/release/v0.1-checklist.md
  - 10-step tester acceptance test (install → capture → cleanup →
    task → MicroSteps → timer → history search)
  - Must-ship list per surface (product, onboarding, artefacts, docs,
    quality gates, trust+security, release-blockers, smoke-test
    matrix)
  - Activation metrics for private beta (3 min to first capture, 3
    captures in 24h, 7-day return, etc.) + v0.1 public launch
    (20 install, 15 first-capture, 10 return, 5 pay-£39)
  - Pre-tag verification sequence
  - Explicit out-of-scope list (Garden Inbox, Phases B-E/G/I/J, etc.)

docs/release/v0.1-known-limitations.md
  - User-facing rewrite, not engineer-speak
  - Power assertions per platform (Linux idle / macOS App Nap / Windows
    sleep) with practical workarounds
  - MCP read-only/local-only posture with the
    "all transcripts visible to your wired client" honest nuance
  - AI cleanup/extraction failure table — what fails, what you see,
    what's preserved
  - Settings page progressive-disclosure status
  - Internal engine refactor (orchestrator dormant) framed for users
  - Explicit "what's NOT in v0.1" call-outs
  - Reporting issues + crash-dump location

docs/release/v0.2-garden-roadmap.md
  - Headline: "review cards for turning messy dictations into notes,
    tasks, topics and links" — tangible, not PKM-overloaded
  - Garden Inbox scope (raw / cleaned / suggested title-type-folder-
    project / extracted tasks / suggested tags / possible links /
    confidence / Accept-Edit-Park-Archive)
  - Engine architecture Phases B-E pairing
  - Explicit "NOT in v0.2" list (no graph, no canvas, no PKM marketing,
    no cloud provider, no premium voices)
  - Open decisions for v0.2 scope freeze deferred until v0.1 ships +
    20 testers run

docs/release/how-lumotia-is-built.md
  - Public-facing trust page; honest disclosure that AI-assisted
    human-directed, then evidence
  - The real silent-data-loss bug the drill caught (Phase A.7 fix
    ff8dda0) framed as proof the process works
  - Phase B atomiser audit: 9 surgical fixes including the FIFO hang,
    LlmEngine unload race, purge-vs-restore SELECT-then-DELETE race
  - Supply-chain pre-flight (npm audit signatures + --ignore-scripts +
    pinned dev deps + pinned rust toolchain)
  - MCP read-only audit + LLM failure audit cross-referenced
  - Anti-patterns explicitly avoided (no telemetry exfiltration, no
    silent AI dependency, no "audit log later", etc.)
  - Calibrated to "AI use is survivable; sloppy undisclosed untested
    AI use is not" — RPCS3 framing cited

Verification:
- cargo fmt --check: clean (no Rust changed)
- All four docs are user-readable, not commit-log-derivative
- Cross-references resolve (every internal path quoted exists)
2026-05-14 21:49:54 +01:00
b6b7e8e86c agent: lumotia — Phase B dogfood plan — B.2-B.15 audit trail + finishing summary
Records the per-item verdict + commit hash for every Phase B audit item
(B.2 through B.15). Status block flipped to Complete 2026/05/14. Items
table moved every row from Pending → Done or Documented pass with a
one-paragraph outcome summary. Each Done item also has a full
section in the Done items list, mirroring B.1's existing structure
(surface, why it matters, fix, verification).

Surgical commits in the audit pass:
  643985d B.2 supervisor doc + test name match detach semantics
  31e3f5a B.3 download_impl unlinks .part on ResumeUnsupported
  20ef6c4 B.4 atomic DELETE RETURNING in purge_deleted_transcripts
  d8fa4ff B.5 resolve_export_path follows symlink before containment
  7f0e1b0 B.6 capability JSON mirror invariant pinned
  f252c1b B.7 unload() honours the loading flag
  813f024 B.8 storage crate emits via tracing (was log crate)
  401b6c3 B.9 strip <think>…</think> reasoning before JSON-envelope scan
  1c4ac98 B.10 vitest regression for focusTimer expired-rehydrate

Documented passes (no commit, recorded reasoning in plan): B.11, B.12,
B.13, B.14, B.15.

Phase A baseline gates verified green after the audit pass:
  cargo test --workspace      → 417 / 0 (was 409 baseline, +8 new tests)
  cargo fmt --check           → clean
  cargo clippy --workspace ...→ clean
  npm run test                → 13 / 13 (was 12, +1 new test)
  npm run check               → 0 errors / 0 warnings across 4015 files

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 20:44:55 +01:00
e993786700 agent: lumotia — Phase B dogfood plan + B.1 audit trail
Captures the 15-item Phase B plan (code-atomiser-fix wave verification) at
docs/superpowers/plans/2026-05-14-phase-b-dogfood-plan.md so the per-item
methodology, status, and findings survive across sessions.

B.1 already done (commit 6c212a0) — full audit trail in the Done items
section: 8 existing unit tests inventory, the misleading start_live
lifecycle comment that was the only real residual, and the documented
pass on the Race-B end-to-end gap per the existing SAFETY annotation.

B.2-B.15 listed with commit references + pending status. Same methodology
per item: orient on commit, survey existing coverage, identify real
residuals, surgical fix or pass, commit. Anti-patterns section captures
the decisions made on B.1 so future me does not re-litigate them.
2026-05-14 19:11:41 +01:00
18a64f5c56 agent: lumotia — Phase A.3 remove dead migration_sentinel method + fix architecture-map claim
Phase A.3 finding: AppPaths::migration_sentinel was added with intent
during the rebrand-architecture phase but never wired to any caller.
Exhaustive grep across crates/ src-tauri/ src/ docs/ surfaces:

  - 1 definition (paths.rs)
  - 1 architecture-map description that ASSERTS the method is in use
  - 0 production callers
  - 0 test references

Both boot-time migrations (migrate_legacy_data_dir +
migrate_tauri_app_data_dir_with_paths) are idempotent by construction:
each re-probes the legacy path via Path::exists() on every boot and
short-circuits on the steady state. A sentinel file would optimise the
probe but is not required for correctness; one syscall per legacy
candidate at startup is negligible.

Per the atomiser principle of removing dead surface area rather than
keeping stale promises:
  - Delete AppPaths::migration_sentinel entirely
  - Update docs/architecture-map/.../core-paths.md to describe the actual
    idempotency model (re-probing) rather than the sentinel pattern that
    was never implemented
  - Steer future migrations toward storage/src/migrations.rs schema_version
    (transactional, survives backup/restore) rather than reintroducing
    filesystem sentinels

Verification:
- cargo test -p lumotia-core paths::: 17/17 (no test relied on the method)
- cargo clippy -p lumotia-core --all-targets -- -D warnings: clean

Phase A.4 (stray-magnotia string scan): clean. Every magnotia reference
in the tree is legitimate — migration source paths, documentation, or
test fixtures. The rebrand cascade was thorough.
2026-05-14 07:23:02 +01:00
094b533ef2 agent: code-atomiser-fix — surface capture-thread drops + bypass validation requeue cap
dropped_chunks was incremented on cpal-callback channel-full and
validation requeue overflow but never read by the live session, so
the UI's dropped_audio_ms missed callback-level losses entirely.
Architecture doc had flagged this as a TODO. Also: the 350ms
validation buffer was requeued via try_send into the same 32-slot
channel, silently dropping past the cap on small-buffer audio hosts
(WASAPI exclusive, low-latency ALSA at 256 frames -> ~65 chunks).

Fix: live runtime reads MicrophoneCapture::dropped_chunks() on each
recv_audio tick (LiveSessionRuntime::poll_capture_drops) and converts
the per-chunk-duration delta into the dropped_audio_ms surfaced to
the UI overload status. Per-chunk duration is derived from the most
recent AudioChunk's sample_rate + samples-per-channel so it adapts
to whatever rate cpal is delivering at. Validation requeue moved
from try_send into the bounded channel onto a VecDeque<AudioChunk>
returned alongside the Receiver; ActiveCapture drains the replay
buffer before reading rx in recv_audio, bypassing the 32-slot cap
entirely. Architecture doc updated to remove the TODO and document
the new pre-roll path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 14:39:14 +01:00
2491c7a7dd agent: lumotia-rebrand — fix Codex cross-model review blockers
Some checks failed
check / cargo check (macos-latest) (push) Has been cancelled
check / cargo check (ubuntu-22.04) (push) Has been cancelled
check / cargo check (windows-latest) (push) Has been cancelled
check / svelte build + lint (push) Has been cancelled
Codex independent review found 11 blockers post-cascade. All addressed.

CRITICAL (data-loss / crash):

10. crates/core/src/paths.rs — migrate_legacy_data_dir_inner used
    fs::rename which fails with EXDEV when source + target are on
    different filesystems (encrypted-home, bind mounts, separate
    $XDG_DATA_HOME partition). Combined with the Phase 5 QC fix that
    made migration errors fatal, this would crash on first launch
    for any user whose data dir spans filesystems. Added
    rename_or_copy_tree() that falls back to copy_dir_recursive +
    remove_dir_all on CrossesDevices / errno 18 (EXDEV). Symlinks
    preserved verbatim. Same fallback applied to magnotia.db ->
    lumotia.db inside the dir.

11. Added 4 unit tests: copy_dir_recursive preserves nested
    structure, rename_or_copy_tree same-filesystem happy path,
    is_cross_device classifies CrossesDevices kind + raw errno 18.

Doc residuals (blockers 1-9):

1. crates/cloud-providers/Cargo.toml — "Wyrdnote pending rebrand"
   description.
2. crates/cloud-providers/src/provider.rs — module docs + test
   fixture Wyrdnote refs.
3. crates/transcription/src/orchestrator.rs — module docs + test
   fixture Wyrdnote refs.
4. docs/roadmap/2026-05-10-pkm-phase-tooling-shortlist.md — phase
   name + outputs/wyrdnote path refs.
5. docs/architecture-map/04-llm-formatting-mcp/llm-tests.md —
   MAGNOTIA_LLM_TEST_MODEL env var.
6. .../cloud-providers-stubs.md — MAGNOTIA_API_KEY_*.
7. docs/architecture-map/03-audio-transcription/tests-and-fixtures.md
   — MAGNOTIA_WHISPER_*.
8. docs/gpu-tuning/plan.md — MAGNOTIA_BENCH_RUN.
9. docs/superpowers/specs/2026-05-09-battery-gpu-aware-thread-tuning-
   design.md + corresponding plan — MAGNOTIA_POWER_STATE_OVERRIDE,
   MAGNOTIA_INFERENCE_THREADS.

cargo test --workspace: 343 pass / 0 fail (up from 339; +4 EXDEV
fallback tests).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 13:39:21 +01:00
f093d18a5e agent: lumotia-rebrand — final residuals (HANDOVER + arch-map readme + ui-kit React fn)
Some checks failed
check / cargo check (macos-latest) (push) Has been cancelled
check / cargo check (ubuntu-22.04) (push) Has been cancelled
check / cargo check (windows-latest) (push) Has been cancelled
check / svelte build + lint (push) Has been cancelled
Phase 15.1 final-grep residuals:
- HANDOVER.md "Rebrand note" + Phase 10b row updated to reflect that
  the cascade completed 2026/05/13 (15 phases, both repos, QC-gated).
- HANDOVER.md two surviving sed artefacts: "Lumotia -> Lumotia" line
  restored to "Magnotia -> Lumotia" historical context;
  MAGNOTIA_LLM_TEST_MODEL test gate -> LUMOTIA_LLM_TEST_MODEL.
- src/design-system/ui_kits/index.html: MagnotiaApp React function ->
  LumotiaApp (sed boundary missed the no-separator boundary).
- docs/architecture-map/README.md: MAGNOTIA_LLM_TEST_MODEL doc note.

Preserved (audit trail):
- docs/handovers/ — historical handover docs.
- docs/superpowers/plans/2026-05-12-engine-slop-residuals.md and
  -area-a-storage-errors-survey.md — describe the slop-pass work
  using the names current at the time.
- build/index.html, package-lock.json — regenerate on next build/install.

cargo test --workspace: 339 pass / 0 fail. npm run check: 0 errors.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 13:19:34 +01:00
26c7307607 agent: lumotia-rebrand — docs, scripts, root config, residuals
Some checks failed
check / cargo check (macos-latest) (push) Has been cancelled
check / cargo check (ubuntu-22.04) (push) Has been cancelled
check / cargo check (windows-latest) (push) Has been cancelled
check / svelte build + lint (push) Has been cancelled
Phase 9 of the rebrand cascade. Sweep covers everything the Phase 8
frontend pass deliberately skipped: docs/, root markdown, scripts,
Cargo.toml descriptions, code comments that survived earlier
word-boundary sed, plus a handful of identifiers caught on the final
verify pass.

transcription-app changes:
- README.md, HANDOVER.md, KNOWN-ISSUES.md, run.sh — magnotia/Magnotia
  -> lumotia/Lumotia.
- docs/ — sweep across all subdirs except docs/handovers/ (preserved
  as immutable audit trail). Includes architecture-map references
  to magnotia_core::*, magnotia_storage::*, etc. now pointing at
  lumotia_*; dev-setup.md tracing output examples (lumotia_startup
  target); brief/ + superpowers/ + issues/ + whisper-ecosystem/ +
  audit/.
- Cargo.toml descriptions on 9 crates (core, audio, cloud-providers,
  hotkey, llm, mcp, plus referenced others).
- crates/core/src/{error,hardware,recommendation,paths}.rs +
  crates/audio/src/wav.rs + crates/llm/src/model_manager.rs +
  crates/cloud-providers/src/keystore.rs + crates/mcp/src/lib.rs —
  doc comments and a model-manager user-agent string.
- Caught on final pass: BroadcastChannel("magnotia_task_sync") -> ...
  ("lumotia_task_sync"); magnotia_locale i18n localStorage key
  renamed + migration shim added; CSS keyframe names
  magnotiaPulse / magnotiaBar / magnotiaFade renamed in the design-
  system kit; magnotia_viewer_item / magnotia_viewer_mode handoff
  keys renamed in HistoryPage + viewer/+page.svelte; src/assets/
  wordmark.svg text.
- src-tauri/src/lib.rs comment cleanup ("magnotia era" was sed'd
  to "lumotia era" earlier — restored).

Preserved (intentional):
- crates/core/src/paths.rs — keeps "magnotia" / "Magnotia" / ".magnotia"
  legacy detection strings in legacy_and_target_paths() so the
  migration shim can still find user data from the magnotia era.
- src/lib/stores/{page,focusTimer}.svelte.ts + src/lib/i18n/index.ts
  — migration call sites reference the legacy magnotia keys
  deliberately.
- docs/handovers/ — historical audit trail.

cargo build --workspace passes. npm run check: 0 errors / 0 warnings
(3958 files). cargo test --workspace: 339 pass / 0 fail.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 12:38:03 +01:00
b0d4ac8de1 docs(phase10a): re-validation pass entry for 2026/05/12 stack
Some checks failed
check / cargo check (macos-latest) (push) Has been cancelled
check / cargo check (ubuntu-22.04) (push) Has been cancelled
check / cargo check (windows-latest) (push) Has been cancelled
check / svelte build + lint (push) Has been cancelled
Smoke checks (native window, Settings, Record, no error toasts) PASS on
the post-residuals-B/tracing/Area-A stack. Hermes session crashed
before the longer-form dogfood pass (transcribe + LLM cleanup + tagging)
could run; the LLM tagging crash from 2026/05/10 remains the
outstanding release-blocker. Tracing pipeline confirmed working under
the new default filter.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 23:45:32 +01:00
c55b0aaae0 docs: update residuals status after tracing and storage passes
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 23:27:15 +01:00
a36ae7e068 agent: remove legacy string storage error variant
Commit 52565ea migrated storage to magnotia_storage::Error and flattened
typed storage failures into MagnotiaError::Storage { kind, operation,
detail }. No production code constructs the old
MagnotiaError::StorageError String variant anymore.

Remove the legacy variant so new storage failures cannot regress back to
stringly-typed errors.

Also updates living architecture-map docs that referenced the old
variant (core-error.md variant table, storage-overview.md
SQLITE_BUSY note, storage-crud-profiles.md duplicate-name + default-
profile-rename notes, storage-crud-transcripts.md pre-flight FK check
note) and one stale code comment in crates/storage/src/database.rs's
duplicate-name test. Survey doc + old residuals plan + phase8 historical
plan deliberately left alone — they're audit trail of how the migration
was decided, not living docs.

Pre-existing doc rot flagged but not fixed (Other(String) and
Io(std::io::Error) rows in core-error.md are about variants that
already don't match the actual enum shape — separate doc cleanup pass).

Verification:
- cargo fmt --all -- --check
- cargo check -p magnotia-core
- cargo check -p magnotia-storage
- cargo check --workspace --all-targets
- cargo test -p magnotia-storage — 60 passed, 0 failed
- cargo test --workspace --lib — all green
- rg 'StorageError\(' crates/ src-tauri/src/ — zero hits
- rg 'StorageError' crates/ src-tauri/src/ docs/architecture-map/ — zero
- rg 'Other\(String\)' crates/ src-tauri/src/ — zero

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 23:08:56 +01:00
fdab77776c docs(area-a): storage error inventory + proposed typed taxonomy
Pre-migration survey for engine-slop residuals Area A. Catalogues every
MagnotiaError::StorageError construction site in the storage crate
(78 total across database.rs and migrations.rs), groups by failure
mode, proposes a typed magnotia_storage::Error enum with a serde-
friendly MagnotiaError::Storage { kind, operation, detail } variant on
top, and flags 6 ambiguities + 3 migration risk classes.

Key findings the residuals plan did not capture:
- StorageError is a String variant on MagnotiaError, not a separate
  enum — there is nothing called StorageError in the storage crate.
- Actual site count is 78, not the ~25 the residuals plan estimated.
- Tauri commands stringify every error before crossing into the
  frontend (Result<T, String>), so MagnotiaError's Serialize impl is
  presently unused at the FE/BE boundary. Area E owns that fix.
- Zero Other(String) sites in storage — already cleaned in db654de.

No code changes. Migration awaits decisions on the 6 ambiguous cases
in §"Ambiguous cases / decisions needed".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 22:39:27 +01:00
792fb5ea08 agent: dev launcher — own Linux env-var contract, add dev:tauri, doc sweep
The 2026-05-12 engine-slop pass removed runtime std::env::set_var mutation from src-tauri/src/lib.rs and replaced it with warn_if_x11_env_unset_on_wayland. With no launcher owning the contract, Linux Wayland dogfood was about to regress.

run.sh:
- now owns Linux launcher env defaults via case "$(uname -s)"
  LIBCLANG_PATH=/usr/lib64/llvm21/lib64 (user-set wins)
  WEBKIT_DISABLE_DMABUF_RENDERER=1 (always on Linux; user-set wins)
  GDK_BACKEND=x11, WINIT_UNIX_BACKEND=x11 (Wayland only; user-set wins)
- 60s Vite readiness timeout
- detects early Vite exit (kill -0 + wait) instead of hanging forever
- trap installed before wait so Ctrl-C cleans up
- args forwarded: ./run.sh --release etc.
- non-exec final Tauri launch preserved so cleanup trap fires

package.json:
- "dev:tauri": "./run.sh" — canonical discoverable dev command

Docs:
- README, dev-setup, architecture-map runtime + launcher pages updated with the new contract; canonical command is npm run dev:tauri (./run.sh as direct equivalent)
- dev-launcher-and-scripts.md replaces the incorrect "kills process group" claim with honest "kills the spawned npm process"
- dev-setup.md path /CORBEL-Projects/magnotia → /CORBEL-Projects/transcription-app
- gpu-tuning/plan.md gets a superseded note rather than rewriting the original rationale
- engine-slop-residuals.md gains Area F (packaged-binary launcher contract) with honest wrapper-vs-.desktop trade-off documented

Verification: bash -n run.sh; shellcheck clean; cargo check -p magnotia green; npm pkg get 'scripts.dev:tauri' returns "./run.sh"; stale-ref sweep clean across living docs.
2026-05-12 22:05:33 +01:00
db654deecc agent: engine slop pass — DSP, typed errors, regex parsing, tracing, audit fixes
External code review on 2026-05-12 rated the codebase 4/10 across audio DSP, error typing, JS injection, env-var safety, ALSA parsing, and async logging. This commit lands the prognosis-level fixes plus three audit follow-ups.

Audio/DSP:
- StreamingResampler/rubato confirmed in the live capture path
- regression test at 12 kHz (rms < 0.01, ~40 dB) catches naive decimation
- near-Nyquist test at 9 kHz (rms < 0.05, ~26 dB) exercises transition band

Core errors:
- Other(String) removed; ProviderNotRegistered introduced
- Io variant restructured as struct with kind/message/raw_os_error
- FileNotFound display quotes paths
- Configuration variant removed (unused)

Core types:
- ModelId, EngineName backed by Cow<'static, str>; const borrowed ctor
- Megabytes::from_gb takes u64 (was f64)
- AudioSamples::sample_rate is NonZeroU32; zero-rate defensive branch removed

Capture:
- /proc/asound/cards parsing rewritten as anchored regex (OnceLock)
- regression test covers product names with embedded colons
- monitor_pattern_detection test restored alongside the regex test
- DEAD_SILENCE_FLOOR promoted to module-level with rationale
- DEVICE_VALIDATION_MS, SILENCE_RMS_FLOOR documented with field-observation rationale
- RMS validation loop made idiomatic
- eprintln! migrated to tracing with structured fields and targets

Tauri startup:
- unsafe std::env::set_var removed; ensure_x11_on_wayland renamed to warn_if_x11_env_unset_on_wayland (launcher/wrapper owns env-var contract)
- DB init + log prune + preferences load collapsed to one block_on
- build_preferences_script rewrites JS injection from JSON.parse string to direct object literal plus malformed-JSON guard and unit tests
- WebKitGTK microphone auto-grant logs warning at startup
- tracing subscriber initialised at top of run() (warn,magnotia=info,... on stderr; honors RUST_LOG); previously eprintln→tracing migration was silent because no subscriber existed

Filename counter:
- RECORDING_COUNTER uses SeqCst

Tests: cargo test --workspace --lib green (322 passed, 0 failed across 10 crates).

Three independent audits (original cleanup → Wren → fresh Codex subagent) concur on no critical findings.

Deferred to docs/superpowers/plans/2026-05-12-engine-slop-residuals.md: storage-layer typed errors, remaining eprintln→tracing sweep, capture actor-model refactor, property-based DSP testing, frontend/backend error boundary cleanup.
2026-05-12 22:03:58 +01:00
b463c32f17 chore: stabilize current head before Phase 10a QC 2026-05-10 23:00:25 +01:00
c95a5da077 docs(roadmap): bookmark SIE + adjacent embeddings/rerank/extract servers for PKM phase
Wyrdnote scales from voice-first dictation today to local-first
semantic PKM workbench tomorrow per the engine architecture spec.
The PKM phase needs a serving stack for embeddings + reranking +
entity extraction; this note bookmarks SIE (Superlinked Inference
Engine, Apache-2.0) as the trigger candidate plus six adjacents
to bake off against when the PKM phase lands.

Deferred because (1) PKM sits post-public-beta and infrastructure
decisions today would generalise poorly to a Q4 2026 selection;
(2) the candidates evolve fast; (3) Wyrdnote's local-first +
single-consumer-GPU constraint rules out a today-style bake-off
without real PKM-shape workload to test against.

Decision dimensions captured for the future evaluator: self-host
footprint, cold-start latency, throughput, quality on a Wyrdnote
eval set, reranker availability, extract/NER capability,
OEM-licensability against AGPL-3.0+dual-licence stack, telemetry
posture. Re-evaluation triggers documented.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 21:27:32 +01:00
jars
a1f3f3f134 docs: architecture map (initial 5-slice generation, 105 pages)
Five-slice navigable map of the entire codebase under
docs/architecture-map/. Each slice is a self-contained
breadcrumbed sub-tree:

  01-frontend (16)              Svelte/SvelteKit UI
  02-tauri-runtime (26)         src-tauri commands + lifecycle
  03-audio-transcription (16)   audio + transcription crates
  04-llm-formatting-mcp (19)    llm, ai-formatting, mcp, cloud
  05-core-storage-hotkey-build  core, storage, hotkey, workspace,
                          (26) CI, dev glue

Plus master README.md and data-flow-end-to-end.md tracing
audio bytes from microphone to FTS5 search to MCP read.

Generated by 5 parallel subagents on 2026/05/09 against
HEAD 3c47000. Each page has YAML frontmatter, file:line code
refs, sibling cross-links, plain-English summaries.

Aggregated debt surfaced (full lists in master README):
RB-08 macOS power assertion, schema head drift v14 vs v15,
VAD blocked on ort version conflict, streaming primitives
not wired into live.rs, no prompt versioning, MCP has no
auth, cloud-providers in-memory keystore, SettingsPage
2 484 LOC, commands/live.rs 1 737 LOC, dual theme system,
brand rename to Lumenote pending across the codebase.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 14:04:13 +01:00
jars
c46c0a5ce9 docs: implementation plan for battery- and GPU-aware thread tuning
Bite-sized TDD plan implementing the design at
docs/superpowers/specs/2026-05-09-battery-gpu-aware-thread-tuning-design.md.

8 phases, ~13 commits:
- Phase 1: power.rs (PowerState enum, sysfs parser, probe + overrides,
  10s TTL cache)
- Phase 2: tuning.rs (Workload enum, helper, battery clamp, GPU clamp,
  per-process logging)
- Phase 3: vulkan_loader_available moves from src-tauri to magnotia-core
- Phase 4: whisper backend wires through new helper
- Phase 5: LLM call site wires through new helper after model load
- Phase 6: remove old constants::inference_thread_count facade
- Phase 7: thread_sweep.rs prints 4-panel power-aware RTF table
- Phase 8: manual battery validation smoke

Each task is TDD: write failing test, run, implement, run, commit.
Tests live in unit-test modules inside power.rs and tuning.rs.

Override design uses an in-process with_override(state, |closure|)
helper for unit tests (cargo runs them in parallel; env-var path
would race) and MAGNOTIA_POWER_STATE_OVERRIDE env var for
integration tests like thread_sweep.rs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 11:01:21 +01:00
jars
200c4fb447 docs: battery- and GPU-aware inference thread tuning design
Spec for two new clamps on the existing inference_thread_count helper:
- Battery clamp: drop to physical/2 when on battery (Linux sysfs probe;
  macOS/Windows return Unknown, treated as OnAc).
- GPU-offload clamp: 2 threads for fully-offloaded LLM, 4 for Whisper
  (Whisper keeps mel spectrogram, decoder bookkeeping, and beam search
  on CPU even with full Vulkan offload).

Codex + online-research consult: no prior art in llama.cpp, Ollama,
Jan, or mistral.rs. Apple's Low Power Mode is OS-level (P-core
frequency cap), not a published software API. Lumenote would be first
in the open Rust inference-wrapper space; instrumentation matters,
hence the thread_sweep.rs extension + per-process INFO log.

Architecture (Approach B):
- New crates/core/src/power.rs (PowerState, sysfs probe, 10s TTL).
- New crates/core/src/tuning.rs (Workload enum, helper).
- Move vulkan_loader_available() from src-tauri to magnotia-core
  so crates/transcription can call it without a Tauri dep.
- Existing constants::inference_thread_count() becomes deprecated
  facade for one commit, then removed.

GPU-offload detection is intent-based (use_gpu && requested_layers
>= model.n_layer() for LLM; cfg(whisper-vulkan) && libvulkan
resolvable for Whisper). Residency-based detection deferred:
llama-cpp-2 0.1.145 doesn't expose post-load offload count, so a
true outcome flag would need llama_log_set callback parsing or an
upstream PR. Caveat documented in the spec.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 10:36:21 +01:00
d234ef394e docs(readme): refresh bundled LLM list to Qwen3.5/3.6
Some checks failed
check / cargo check (macos-latest) (push) Has been cancelled
check / cargo check (ubuntu-22.04) (push) Has been cancelled
check / cargo check (windows-latest) (push) Has been cancelled
check / svelte build + lint (push) Has been cancelled
audit / cargo audit (push) Has been cancelled
audit / npm audit (push) Has been cancelled
README LLM-formatting section now states four Qwen tiers (Qwen3.5 2B /
4B / 9B + Qwen3.6 27B) and the magnotia-llm crate row reflects the
four-tier registry. The whisper-ecosystem context doc gets the same
refresh and cites unsloth as the GGUF source.

Older roadmap and Phase-0 audit docs left untouched — they are dated
historical artefacts and rewriting them would muddy the audit trail.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 09:59:37 +01:00
c42a144aad agent: audit — Phase 1 lean-pass scan deliverable (read-only, review pending)
Some checks failed
check / cargo check (macos-latest) (push) Has been cancelled
check / cargo check (ubuntu-22.04) (push) Has been cancelled
check / cargo check (windows-latest) (push) Has been cancelled
check / svelte build + lint (push) Has been cancelled
2026-05-01 08:24:53 +01:00
b410c6196b docs(handovers): D1 — move dated HANDOVERs to docs/handovers/ with rebrand-origin note
Some checks failed
check / cargo check (macos-latest) (push) Has been cancelled
check / cargo check (ubuntu-22.04) (push) Has been cancelled
check / cargo check (windows-latest) (push) Has been cancelled
check / svelte build + lint (push) Has been cancelled
2026-05-01 08:05:00 +01:00
Claude
7ff7295567 docs(audit): add fix-areas section to Phase 0 + Phases 1-8 playbook
Some checks failed
check / cargo check (macos-latest) (push) Has been cancelled
check / cargo check (ubuntu-22.04) (push) Has been cancelled
check / cargo check (windows-latest) (push) Has been cancelled
check / svelte build + lint (push) Has been cancelled
Phase 0 update: replaces the loose "quick wins" list with a structured
Fix Areas section organised into impact tiers (A: high-impact README
truth fixes, B: low-effort self-violation fixes, C: structural smells
deferred to Phase 2, D: hygiene). Each task names the file, the change,
the verification command, and the effort estimate.

New playbook: docs/audit/phases-1-8-playbook.md — step-by-step
acquisition-grade audit procedure for the remaining seven phases. Each
phase has goal, inputs, procedure (with concrete commands), deliverable,
acceptance criteria, and time estimate. Designed to be picked up
independently from any phase.
2026-05-01 06:38:54 +00:00
Claude
0b6be94f3e docs(audit): add Phase 0 cartography report
Inventory of workspace shape, LOC, dependency graph, public API surface,
external surfaces (Tauri commands / MCP tools / frontend routes), and a
README↔code drift log. Input for Phase 1 (lean-pass).

Surfaces five concrete README drifts (one HIGH: stores list fiction; two
MED: undocumented Tauri modules and a Moonshine claim with no registry
entry) and three structural smells worth a Phase-2 follow-up.
2026-04-30 14:51:18 +00:00
Claude
89c63891fa chore: rebrand from Kon/Corbie to Magnotia
Replace all instances of the legacy product names "Kon" and "Corbie" with
"Magnotia" across user-facing copy, code identifiers, package names, bundle
ids, file paths, and documentation. Preserves the unrelated "konsole" (KDE
terminal) reference and the parent CORBEL company name.

- Renames 10 Rust crates (kon-* → magnotia-*) and the tauri binary
- Updates package.json, tauri.conf.json (productName + identifier)
- Renames CSS classes (kon-rh-* → magnotia-rh-*) and animations
- Renames brand and roadmap docs
- Regenerates Cargo.lock and package-lock.json

Verified: svelte-check passes; pure-rust crates compile under new names.
2026-04-30 13:06:55 +00:00
cc77befda8 docs(phase10a): static slice audit findings
Some checks failed
check / cargo check (macos-latest) (push) Has been cancelled
check / cargo check (ubuntu-22.04) (push) Has been cancelled
check / cargo check (windows-latest) (push) Has been cancelled
check / svelte build + lint (push) Has been cancelled
Captures the agent-runnable portion of Phase 10a ahead of Jake's
manual walkthrough and feedback-document pass:

- a11y baseline confirmed clean (svelte-check 0/0; consistent
  aria-label + aria-hidden patterns across icon buttons; global
  :focus-visible ring set in design tokens; prefers-reduced-motion
  guards present where motion warrants them)
- WCAG 2.1 AA contrast tables for both themes computed from the
  token list at design-system/colors_and_type.css. Nine pairs miss
  AA-normal; light-theme warning misses AA-large too. Severity
  ranked, suggested token shifts noted as starting points
- CI matrix state: check.yml runs on every push, build.yml has
  never been end-to-end exercised - recommend manual workflow_
  dispatch before tagging v0.1.0
- Clean-install test plan and the Phase 9d walkthrough checklist
  consolidated for the testing session
2026-04-25 01:02:48 +01:00