Brand guidelines (docs/brand/magnotia-brand-guidelines.md §4) say "Never go
below 12px for any text" and "tertiary text must be ≥18px bold or ≥24px
regular". Audit found 246 sub-12px className sites and 166 cases of
text-text-tertiary paired with body sizes.
Bumped text-[9/10/11px] → text-[12px] across 26 .svelte files in src/lib
and src/routes. Promoted text-text-tertiary → text-text-secondary at body
sizes (12-14px) where context allowed; left placeholder pseudo-states,
ternary-conditional inactive states, and line-through "done" states alone
(8 residual pairings, all decorative).
Affects neurodivergent users on 1366×768 budget hardware most directly.
svelte-check: 0 errors, 0 warnings.
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.
Phase 10a a11y audit (2026-04-29) flagged seven inputs across the app
that strip the global 2px :focus-visible outline (defined in app.css:251)
without providing a comparable replacement. Net effect: keyboard users
see at most a 1px border-colour shift on focus, sometimes nothing.
The fix removes the focus:outline-none override so the global rule
applies. Affected inputs:
- FilesPage: file-transcript textarea (F2).
- TasksPage: search input, quick-add input, inline list-edit, new-list
input (T1, T2, T3, plus the new-list rename input).
- HistoryPage: top search, inline title rename, tag-add (H1).
- ImplementationRulesEditor: trigger/surface/task selects + speak-line
input (S7).
- TaskSidebar, WipTaskList: quick-add inputs (S8).
The 1px focus:border-accent on inputs that had it is retained as a
secondary cue; the global 2px ring is now the primary indicator and
matches button focus across the app.
Resolves: F2, T1, T2, T3, H1, S7, S8.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Closes Phase 3 of the 2026-04-23 feature-complete roadmap. Incorporates
the Codex plan-review fixes from this session: profile-free index, tri-
state update command, and de-prioritise-not-hide semantics.
Storage (kon-storage):
- Migration v11 adds `energy TEXT` to `tasks` with a CHECK constraint on
`high | medium | brain_dead | NULL`. Index `(energy, created_at DESC)`
— deliberately not per-profile because the tasks table carries no
profile_id column yet (tracked as a separate gap in HANDOVER).
- `TaskRow.energy: Option<String>` plus `task_row_from` read.
- `insert_task` signature grows by one optional arg (`energy`). Allowed
`too_many_arguments` with a rationale comment — the positional shape
matches the column order and flipping to a params struct would have
rippled through every caller for cosmetic benefit only.
- New `set_task_energy(pool, id, Option<&str>) -> TaskRow`. Lives as its
own function because `update_task` uses COALESCE to let `None` mean
"preserve" — which would make clearing the tag impossible.
- Two new tests: round-trip including explicit NULL clear, and CHECK
constraint rejection of unknown values.
- Tests updated for the v10 → v11 version bump.
Tauri (src-tauri):
- `TaskDto.energy`. `CreateTaskRequest.energy` (optional). Inline
validation against the allowed set before hitting the DB, so frontend
bugs surface as friendly errors instead of CHECK-constraint failures.
- New `set_task_energy_cmd` command mirroring the storage tri-state API.
Frontend (svelte):
- `EnergyLevel` type added to `types/app.ts`. `TaskDto`, `TaskEntry`, and
`TaskDraft` grow an `energy` field.
- `SettingsState.currentEnergy` (persisted) + `matchMyEnergy` (persisted
toggle). Defaults: null + false — no surface change until user opts in.
- `setTaskEnergy(id, EnergyLevel | null)` action on the task store.
Calls the dedicated Tauri command, updates local state, broadcasts to
sibling windows.
- `EnergyChip.svelte` — new component. Cycles unset → High → Medium →
Brain-Dead → unset on click. Colour tokens: accent / warning /
text-tertiary (deliberately not danger-red for Brain-Dead — the brief
is explicit that this state must not feel pathologised).
- Chip rendered on every task row in TasksPage and every row in
WipTaskList. Hidden-until-hover when energy is unset so untagged rows
stay calm; always visible once tagged because the colour is the signal.
- Tasks page header gains a "I feel" segmented control and a
"Match my energy" toggle. When both are active, matching tasks sort
to the top — unset tasks are treated as Medium-equivalent. Nothing is
ever hidden; this is a de-prioritisation, not a filter.
Deferred / out of scope:
- LLM-driven surfacing (brief says "The AI surfaces...") — deterministic
client-side sort is v1; LLM layer is a later phase.
- tasks.profile_id + per-profile energy sort — separate migration.
All green: cargo build + 251 tests + clippy -D warnings (0 warnings)
+ fmt + svelte-check (0/0) + npm run build.
Closes the human-in-the-loop gap from docs/brief/feature-set.md and
Phase 2 of the 2026-04-23 feature-complete roadmap.
Storage (kon-storage):
- Migration v10 adds the `feedback` table: (target_type, target_id,
rating, original_text, corrected_text, context_json, profile_id,
created_at) with CHECK constraints on target_type and rating, plus
indexes on (target_type, rating, created_at DESC) for prompt-time
retrieval and (profile_id, target_type, created_at DESC) for
per-profile scoping.
- New public API: `FeedbackTargetType`, `RecordFeedbackParams`,
`FeedbackRow`, `record_feedback`, `list_feedback_examples`.
- Tests updated — the RB-02 rollback regression now discovers the
real max version at runtime instead of hard-coding v10 for its
poison migration.
LLM (kon-llm):
- `prompts::FeedbackExample` — local shape for few-shot exemplars so
kon-llm stays independent of kon-storage.
- `prompts::build_conditioned_system_prompt` — appends a "here is
the style this user prefers" block to the base system prompt
when examples are available; returns the base prompt unchanged
when empty, so new users and early sessions see generic output.
- `LlmEngine::decompose_task_with_feedback` and
`LlmEngine::extract_tasks_with_feedback` thread examples through
to the builder. The old one-arg variants are preserved and now
call through with an empty slice.
- 4 unit tests covering empty, empty-input-skip, correction-wins,
and thumbs-up-only fallback.
Tauri (src-tauri):
- New commands::feedback module: `record_feedback`,
`list_feedback_examples_cmd`.
- `decompose_and_store` and `extract_tasks_from_transcript_cmd`
now fetch the last 5 positive/neutral feedback rows for their
target type and pass them through to the LLM, wiring the
learning loop end-to-end.
- Shared `to_llm_examples` helper parses the `context_json.input`
field (where the recorder stashes the parent task text / transcript
chunk) back into the exemplar shape.
Frontend (MicroSteps.svelte):
- Thumbs-up and thumbs-down buttons on every micro-step row.
Hover-revealed; the vote recolours the icon; clicking again
clears the local highlight (the row itself stays in the audit
trail).
- Pencil icon + double-click to edit step text. Save flows through
update_task_cmd for persistence and records a correction feedback
row with (original_text, corrected_text) — the highest-value
training signal.
- Parent task text is captured in context_json.input at record time
so the prompt builder can reconstruct the (input, preferred-output)
pair on subsequent decompositions.
- Feedback capture is best-effort — a record_feedback failure never
interrupts the primary action.
What's deferred to a later phase:
- Thumbs + corrections on extracted tasks (same pipeline, different
surface — probably TasksPage after the AI-extraction path)
- Thumbs on transcript cleanup output
- Semantic retrieval over the feedback corpus (once there is enough
data to justify embedding infrastructure; the storage shape is
already ready for it)
Closes the Core MVP gap in docs/brief/feature-set.md ("visual time
representation") and wires the dangling kon:start-timer emit that
MicroSteps.svelte has been firing into the void since the stub was
written. Implements phase 1 of the 2026-04-23 feature-complete
roadmap.
New:
- src/lib/stores/focusTimer.svelte.ts — singleton timer store with
localStorage persistence so a timer started in Dictation survives
page nav, window close, and reopen. Gentle WebAudio chime at
completion (no bundled asset). 250 ms tick. Completion flash for
3 s before auto-clear.
- src/lib/components/FocusTimer.svelte — floating top-right overlay
with SVG progress ring (shrinking colour: accent -> warning in
the final 15% -> success on completion). Cancel + "+1 min" on
hover. Renders nothing when idle.
Wired in +layout.svelte next to ToastViewport.
Two triggers now in the app:
- MicroSteps row 2-min button (pre-existing emit, previously no
listener)
- WipTaskList row 5-min button (new; the brief's "just-start"
from the Now column)
Respects prefers-reduced-motion via the existing
[data-reduce-motion] attribute.
Out of scope, carried to later phases: rhythmic voice anchoring
(Phase 6), custom-duration picker, multi-timer UI, native OS
notification (deferred to Phase 6 with the full nudge pipeline).
Wholesale JS -> TS migration of the frontend — stores, utils, actions,
and all Svelte component scripts adopt type annotations. Compile-time
surfaces (app.d.ts, lib/types/) added for shared DTO types.
Build plumbing:
- package.json: dev:frontend script that runs svelte-kit sync first
- tauri.conf.json: beforeDevCommand points at dev:frontend
- run.sh: dropped the sed-hack that temporarily blanked beforeDevCommand;
now relies on npm run dev:frontend to avoid double-Vite
- jsconfig.json: allowImportingTsExtensions
Preserves all Group 1 behaviour:
- page.svelte.ts keeps loadHistory / loadTasks Tauri-first, no
localStorage; saveTranscriptMeta + mapTranscriptRow + mapTaskRow
intact; update_task_cmd and update_transcript_meta_cmd invocations
carry the correct payload shape.
- Toasts, preferences stores typed without behaviour change.
- Viewer still routes segment edits through saveTranscriptMeta; the
Task 1.5 TODO markers are gone.
taskExtractor.ts is functionally improved during the migration:
- multi-task matches in the same sentence
- list-style shopping-verb expansion (get bread, milk, and cheese)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>