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.
This commit is contained in:
Claude
2026-04-30 13:06:55 +00:00
parent 749403697a
commit 89c63891fa
186 changed files with 1297 additions and 1297 deletions

View File

@@ -182,34 +182,34 @@ Three workflows in `.github/workflows/`:
## Clean-install test plan
Run on a spare user account or a fresh VM, with no prior Corbie /
Kon data. Three iterations: one per platform.
Run on a spare user account or a fresh VM, with no prior Magnotia /
Magnotia data. Three iterations: one per platform.
1. Install the artefact from the platform's `build.yml` output.
2. Launch from a clean shell (`corbie` from PATH, or the .app /
2. Launch from a clean shell (`magnotia` from PATH, or the .app /
Start-menu shortcut).
3. Verify first-run setup flow renders. Walk through the Whisper /
LLM model download for the smallest tier.
4. Confirm app data lands at the expected path:
- Linux: `~/.local/share/kon/` (will become `~/.local/share/
corbie/` after Phase 10b rename).
- macOS: `~/Library/Application Support/com.corbel.kon/`.
- Windows: `%APPDATA%\com.corbel.kon\`.
- Linux: `~/.local/share/magnotia/` (will become `~/.local/share/
magnotia/` after Phase 10b rename).
- macOS: `~/Library/Application Support/com.corbel.magnotia/`.
- Windows: `%APPDATA%\com.corbel.magnotia\`.
5. Record a 10-second brain-dump → cleanup → task extraction.
Confirm no log leakage to stderr that references `target/` or
dev-only paths.
6. Quit the app. Open the SQLite db (`kon.db` for now) and verify
6. Quit the app. Open the SQLite db (`magnotia.db` for now) and verify
`SELECT version FROM schema_version ORDER BY version DESC LIMIT
1` returns `14`.
7. Re-launch. Confirm settings persist, history shows the test
transcript with manual + LLM tags.
8. Optional but recommended: launch with `RUST_LOG=debug` once and
archive the log. Anything referencing `/home/jake/Documents/
CORBEL-Projects/kon/target/` is a dev-leak bug.
CORBEL-Projects/magnotia/target/` is a dev-leak bug.
For Phase 10c this gets re-run after the rename sweep to confirm
the migration shim correctly moves `~/.local/share/kon/`
`~/.local/share/corbie/` and renames `kon.db``corbie.db`.
the migration shim correctly moves `~/.local/share/magnotia/`
`~/.local/share/magnotia/` and renames `magnotia.db``magnotia.db`.
## Walkthrough checklist (deferred from Phase 9d)
@@ -255,7 +255,7 @@ def contrast(c1, c2):
## Anchors
- Roadmap: [docs/roadmap/2026-04-23-corbie-feature-complete-roadmap.md](../../roadmap/2026-04-23-corbie-feature-complete-roadmap.md)
- Roadmap: [docs/roadmap/2026-04-23-magnotia-feature-complete-roadmap.md](../../roadmap/2026-04-23-magnotia-feature-complete-roadmap.md)
- Phase 9 spec: [docs/superpowers/specs/2026-04-24-phase9-polish-debt-design.md](../specs/2026-04-24-phase9-polish-debt-design.md)
- Release-blocker index: [docs/issues/README.md](../../issues/README.md)
- Latest handover: [HANDOVER.md](../../../HANDOVER.md)

View File

@@ -16,7 +16,7 @@
- Branch: `main` (Jake's standing rule — phases ship on main, not feature branches).
- Commit after each task. Format: `feat(gamification): [what changed]`, or `fix(gamification): …` for a within-phase correction. Each task's final step is the commit.
- Test runner on Rust: `cargo test -p kon-storage` (or crate name in workspace). Frontend has **no test runner**`npm run check` is the only type/lint gate; correctness is verified by cargo tests on the backend and manual dogfood on the frontend, deferred to Phase 10a QC.
- Test runner on Rust: `cargo test -p magnotia-storage` (or crate name in workspace). Frontend has **no test runner**`npm run check` is the only type/lint gate; correctness is verified by cargo tests on the backend and manual dogfood on the frontend, deferred to Phase 10a QC.
- British English in user-facing copy.
- No em / en dashes in prose or strings.
@@ -97,7 +97,7 @@ async fn migration_v13_adds_auto_completed_column() {
- [ ] **Step 2: Run test to verify it fails**
Run: `cargo test -p kon-storage migration_v13 -- --nocapture`
Run: `cargo test -p magnotia-storage migration_v13 -- --nocapture`
Expected: FAIL with "no such column: auto_completed" or "expected auto_completed column" depending on which assertion fires first.
- [ ] **Step 3: Add the migration entry**
@@ -130,12 +130,12 @@ In `crates/storage/src/migrations.rs`, append to the `MIGRATIONS: &[(i64, &str,
- [ ] **Step 4: Run test to verify it passes**
Run: `cargo test -p kon-storage migration_v13 -- --nocapture`
Run: `cargo test -p magnotia-storage migration_v13 -- --nocapture`
Expected: PASS.
- [ ] **Step 5: Run the full storage test suite to confirm no regression**
Run: `cargo test -p kon-storage`
Run: `cargo test -p magnotia-storage`
Expected: all existing tests still pass.
- [ ] **Step 6: Commit**
@@ -209,7 +209,7 @@ async fn cascade_sets_auto_completed_on_parent_only() {
- [ ] **Step 2: Run test to verify it fails**
Run: `cargo test -p kon-storage cascade_sets_auto_completed -- --nocapture`
Run: `cargo test -p magnotia-storage cascade_sets_auto_completed -- --nocapture`
Expected: FAIL — parent_auto is 0 because the cascade UPDATE doesn't set the flag yet.
- [ ] **Step 3: Modify the cascade UPDATE**
@@ -223,7 +223,7 @@ if pending == 0 {
.bind(&pid)
.execute(&mut *tx)
.await
.map_err(|e| KonError::StorageError(format!("Auto-complete parent failed: {e}")))?;
.map_err(|e| MagnotiaError::StorageError(format!("Auto-complete parent failed: {e}")))?;
}
```
@@ -240,18 +240,18 @@ if pending == 0 {
.bind(&pid)
.execute(&mut *tx)
.await
.map_err(|e| KonError::StorageError(format!("Auto-complete parent failed: {e}")))?;
.map_err(|e| MagnotiaError::StorageError(format!("Auto-complete parent failed: {e}")))?;
}
```
- [ ] **Step 4: Run test to verify it passes**
Run: `cargo test -p kon-storage cascade_sets_auto_completed -- --nocapture`
Run: `cargo test -p magnotia-storage cascade_sets_auto_completed -- --nocapture`
Expected: PASS.
- [ ] **Step 5: Run the full storage test suite**
Run: `cargo test -p kon-storage`
Run: `cargo test -p magnotia-storage`
Expected: all tests pass.
- [ ] **Step 6: Commit**
@@ -317,7 +317,7 @@ async fn uncomplete_clears_auto_completed_on_parent() {
- [ ] **Step 2: Run test to verify it fails**
Run: `cargo test -p kon-storage uncomplete_clears_auto_completed -- --nocapture`
Run: `cargo test -p magnotia-storage uncomplete_clears_auto_completed -- --nocapture`
Expected: FAIL on the `parent_auto` assertion (still 1).
- [ ] **Step 3: Modify both UPDATE statements in `uncomplete_task`**
@@ -357,12 +357,12 @@ sqlx::query(
- [ ] **Step 4: Run test to verify it passes**
Run: `cargo test -p kon-storage uncomplete_clears_auto_completed -- --nocapture`
Run: `cargo test -p magnotia-storage uncomplete_clears_auto_completed -- --nocapture`
Expected: PASS.
- [ ] **Step 5: Run the full storage test suite**
Run: `cargo test -p kon-storage`
Run: `cargo test -p magnotia-storage`
Expected: all tests pass.
- [ ] **Step 6: Commit**
@@ -507,7 +507,7 @@ async fn list_recent_completions_uses_local_day_boundary() {
- [ ] **Step 2: Run tests to verify they fail**
Run: `cargo test -p kon-storage list_recent_completions -- --nocapture`
Run: `cargo test -p magnotia-storage list_recent_completions -- --nocapture`
Expected: FAIL — function not defined.
- [ ] **Step 3: Add the struct and function**
@@ -562,7 +562,7 @@ pub async fn list_recent_completions(
.bind(format!("-{} days", days - 1))
.fetch_all(pool)
.await
.map_err(|e| KonError::StorageError(format!("List recent completions failed: {e}")))?;
.map_err(|e| MagnotiaError::StorageError(format!("List recent completions failed: {e}")))?;
let lookup: std::collections::HashMap<String, u32> = rows
.into_iter()
@@ -574,7 +574,7 @@ pub async fn list_recent_completions(
sqlx::query_as("SELECT DATE('now', 'localtime')")
.fetch_one(pool)
.await
.map_err(|e| KonError::StorageError(format!("Get local today failed: {e}")))?;
.map_err(|e| MagnotiaError::StorageError(format!("Get local today failed: {e}")))?;
let today = today_row.0;
let mut series = Vec::with_capacity(days as usize);
@@ -588,7 +588,7 @@ pub async fn list_recent_completions(
.bind(format!("-{offset} days"))
.fetch_one(pool)
.await
.map_err(|e| KonError::StorageError(format!("Compute spine day failed: {e}")))?;
.map_err(|e| MagnotiaError::StorageError(format!("Compute spine day failed: {e}")))?;
let count = lookup.get(&day).copied().unwrap_or(0);
series.push(DailyCompletionCount { day, count });
}
@@ -607,17 +607,17 @@ pub use database::{DailyCompletionCount, list_recent_completions};
- [ ] **Step 4: Run tests to verify they pass**
Run: `cargo test -p kon-storage list_recent_completions -- --nocapture`
Run: `cargo test -p magnotia-storage list_recent_completions -- --nocapture`
Expected: all 4 new tests PASS.
- [ ] **Step 5: Run the full storage test suite**
Run: `cargo test -p kon-storage`
Run: `cargo test -p magnotia-storage`
Expected: all tests pass.
- [ ] **Step 6: Verify clippy + fmt**
Run: `cargo clippy -p kon-storage -- -D warnings && cargo fmt --check`
Run: `cargo clippy -p magnotia-storage -- -D warnings && cargo fmt --check`
Expected: clean.
- [ ] **Step 7: Commit**
@@ -647,7 +647,7 @@ EOF
- [ ] **Step 1: Add the import at the top of `src-tauri/src/commands/tasks.rs`**
Update the existing `use kon_storage::{...}` block (currently starting at line 10) to include the new symbols. Add `DailyCompletionCount, list_recent_completions as db_list_recent_completions` alongside the existing entries.
Update the existing `use magnotia_storage::{...}` block (currently starting at line 10) to include the new symbols. Add `DailyCompletionCount, list_recent_completions as db_list_recent_completions` alongside the existing entries.
- [ ] **Step 2: Add the command at the end of `src-tauri/src/commands/tasks.rs`**
@@ -676,12 +676,12 @@ In `src-tauri/src/lib.rs`, inside the `invoke_handler!` block, below the existin
- [ ] **Step 4: Compile**
Run: `cargo build -p kon`
Run: `cargo build -p magnotia`
Expected: clean build.
- [ ] **Step 5: Verify clippy + fmt**
Run: `cargo clippy -p kon -- -D warnings && cargo fmt --check`
Run: `cargo clippy -p magnotia -- -D warnings && cargo fmt --check`
Expected: clean.
- [ ] **Step 6: Commit**
@@ -691,7 +691,7 @@ git add src-tauri/src/commands/tasks.rs src-tauri/src/lib.rs
git commit -m "$(cat <<'EOF'
feat(gamification): list_recent_completions_cmd Tauri wrapper
Thin wrapper over kon_storage::list_recent_completions, parameterised
Thin wrapper over magnotia_storage::list_recent_completions, parameterised
by day count. Serialises to camelCase JSON (day, count).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@@ -769,10 +769,10 @@ EOF
//
// Refresh triggers:
// - module load (first time)
// - kon:task-completed (from page.svelte.ts completeTask)
// - kon:step-completed (from MicroSteps.svelte)
// - kon:task-uncompleted (new event — emitted by uncompleteTask)
// - kon:task-deleted (new event — emitted by deleteTask)
// - magnotia:task-completed (from page.svelte.ts completeTask)
// - magnotia:step-completed (from MicroSteps.svelte)
// - magnotia:task-uncompleted (new event — emitted by uncompleteTask)
// - magnotia:task-deleted (new event — emitted by deleteTask)
// - window focus (for day rollover while the app stayed open
// past midnight)
//
@@ -813,10 +813,10 @@ if (typeof window !== "undefined") {
const handler = () => {
refresh().catch(() => {});
};
window.addEventListener("kon:task-completed", handler);
window.addEventListener("kon:step-completed", handler);
window.addEventListener("kon:task-uncompleted", handler);
window.addEventListener("kon:task-deleted", handler);
window.addEventListener("magnotia:task-completed", handler);
window.addEventListener("magnotia:step-completed", handler);
window.addEventListener("magnotia:task-uncompleted", handler);
window.addEventListener("magnotia:task-deleted", handler);
window.addEventListener("focus", handler);
if (hasTauriRuntime()) {
@@ -1034,12 +1034,12 @@ EOF
---
### Task 10: Dispatch `kon:task-uncompleted` + `kon:task-deleted`
### Task 10: Dispatch `magnotia:task-uncompleted` + `magnotia:task-deleted`
**Files:**
- Modify: `src/lib/stores/page.svelte.ts``uncompleteTask` (line 470-479) and `deleteTask` (line 438-451).
- [ ] **Step 1: Emit `kon:task-uncompleted` from `uncompleteTask`**
- [ ] **Step 1: Emit `magnotia:task-uncompleted` from `uncompleteTask`**
Current body:
```ts
@@ -1060,11 +1060,11 @@ Replace the try-block body with:
await invoke("uncomplete_task_cmd", { id });
applyLocalTaskUpdate(id, { done: false, doneAt: null });
if (typeof window !== "undefined") {
window.dispatchEvent(new CustomEvent("kon:task-uncompleted", { detail: { id } }));
window.dispatchEvent(new CustomEvent("magnotia:task-uncompleted", { detail: { id } }));
}
```
- [ ] **Step 2: Emit `kon:task-deleted` from `deleteTask`**
- [ ] **Step 2: Emit `magnotia:task-deleted` from `deleteTask`**
Current body:
```ts
@@ -1087,7 +1087,7 @@ Add the dispatch inside the success path, right after `broadcastTasks();`:
```ts
if (typeof window !== "undefined") {
window.dispatchEvent(new CustomEvent("kon:task-deleted", { detail: { id } }));
window.dispatchEvent(new CustomEvent("magnotia:task-deleted", { detail: { id } }));
}
```
@@ -1105,7 +1105,7 @@ feat(gamification): emit task-uncompleted + task-deleted events
Phase 8 completionStats store listens on these events to refresh the
daily count. Keeps the badge + sparkline accurate after un-tick / delete
paths, which don't currently fire kon:task-completed.
paths, which don't currently fire magnotia:task-completed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
EOF
@@ -1222,7 +1222,7 @@ Record any deviations in the handover. Do not mark this step complete on compile
### Task 13: Update roadmap and handover
**Files:**
- Modify: `docs/roadmap/2026-04-23-corbie-feature-complete-roadmap.md` (Phase 8 section — mark shipped, fold the revised-dropped-grace-days line into past tense).
- Modify: `docs/roadmap/2026-04-23-magnotia-feature-complete-roadmap.md` (Phase 8 section — mark shipped, fold the revised-dropped-grace-days line into past tense).
- Modify: `HANDOVER.md` (end-of-session summary).
- [ ] **Step 1: Update roadmap Phase 8 status**
@@ -1247,7 +1247,7 @@ Replace the session summary with today's state:
- [ ] **Step 3: Commit**
```bash
git add docs/roadmap/2026-04-23-corbie-feature-complete-roadmap.md HANDOVER.md
git add docs/roadmap/2026-04-23-magnotia-feature-complete-roadmap.md HANDOVER.md
git commit -m "$(cat <<'EOF'
docs(phase8): mark Phase 8 shipped + refresh handover

View File

@@ -6,7 +6,7 @@
**Architecture:** See companion spec for full detail. Four sub-phases: 9a export plumbing, 9b LLM tags, 9c Settings restructure, 9d visual + a11y polish.
**Tech Stack:** Rust + Tauri 2, `tauri-plugin-dialog` (already installed), `kon-llm` (already wired to llama-cpp-2), Svelte 5 runes, TypeScript, Tailwind v4, Lucide icons.
**Tech Stack:** Rust + Tauri 2, `tauri-plugin-dialog` (already installed), `magnotia-llm` (already wired to llama-cpp-2), Svelte 5 runes, TypeScript, Tailwind v4, Lucide icons.
**Spec:** [docs/superpowers/specs/2026-04-24-phase9-polish-debt-design.md](../specs/2026-04-24-phase9-polish-debt-design.md)
@@ -16,7 +16,7 @@
Critical-review pass against the actual codebase (after Codex was unavailable for a cross-model read) surfaced three mismatches between the plan's prescribed code and what the repo actually contains. Implementations adapt as follows.
**1. `kon-llm` API.** Plan referenced `LlamaEngine::generate_chat(messages, config).await`. Actual: `LlmEngine::generate(prompt: &str, config: &GenerationConfig) -> Result<String, EngineError>`*synchronous*, prompt is a single rendered string, no chat-message vec. The engine struct is `LlmEngine` not `LlamaEngine`. Loaded via `engine.load(model_path)` (sync, &self). The closest in-tree analogue to the new `extract_content_tags` is `LlmEngine::cleanup_text` — same crate, same generate-with-prompt shape; copy that pattern. Tasks 7 + 8 code samples are guides, not literals.
**1. `magnotia-llm` API.** Plan referenced `LlamaEngine::generate_chat(messages, config).await`. Actual: `LlmEngine::generate(prompt: &str, config: &GenerationConfig) -> Result<String, EngineError>`*synchronous*, prompt is a single rendered string, no chat-message vec. The engine struct is `LlmEngine` not `LlamaEngine`. Loaded via `engine.load(model_path)` (sync, &self). The closest in-tree analogue to the new `extract_content_tags` is `LlmEngine::cleanup_text` — same crate, same generate-with-prompt shape; copy that pattern. Tasks 7 + 8 code samples are guides, not literals.
**2. Tauri `AppState`.** Plan referenced `state.llm.read().await.engine.as_ref()`. Actual: `AppState.llm_engine: Arc<LlmEngine>` — direct, no RwLock, accessed as `state.llm_engine.as_ref()`. Existing LLM commands file is `src-tauri/src/commands/llm.rs` (already there — do not create a new one).
@@ -43,7 +43,7 @@ Fix in scope (decided 2026-04-24, "do it properly so we don't need to revisit"):
**TDD steps:**
1. Storage test: migration v14 adds `llm_tags TEXT NOT NULL DEFAULT ''` column; pre-existing rows default to empty string.
2. Storage test: `db_update_transcript(.., None, Some("topic:x,intent:y"))` writes only `llm_tags` and leaves `manual_tags` untouched.
3. Tauri command compile-check via `cargo build -p kon`.
3. Tauri command compile-check via `cargo build -p magnotia`.
4. Frontend `npm run check` clean.
Commit message: `feat(phase9): migration v14 + tag persistence wiring`.
@@ -72,7 +72,7 @@ Tasks 8.5 inserted between 8 and 9. Subsequent task numbers (11..16) unchanged.
- Every Phase 9 addition with motion respects `prefers-reduced-motion`.
- Phase 8 gotchas carried forward:
- `$derived` cannot export at `.svelte.ts` module scope — use `export function` instead.
- `#[derive(sqlx::FromRow)]` is not available in `kon-storage` (not expected to fire in this phase; noted for safety).
- `#[derive(sqlx::FromRow)]` is not available in `magnotia-storage` (not expected to fire in this phase; noted for safety).
---
@@ -97,7 +97,7 @@ Tasks 8.5 inserted between 8 and 9. Subsequent task numbers (11..16) unchanged.
- `src/lib/stores/page.svelte.ts` — hydrate / persist `llmTags`.
- `src/lib/utils/frontmatter.ts` — include `llmTags` in `buildFrontmatter` tag union.
- `src/lib/components/CompletionSparkline.svelte` — friendlier aria-label, per-bar `<title>`, `tabindex`, stagger entrance.
- `docs/roadmap/2026-04-23-corbie-feature-complete-roadmap.md` — mark Phase 9 shipped.
- `docs/roadmap/2026-04-23-magnotia-feature-complete-roadmap.md` — mark Phase 9 shipped.
- `HANDOVER.md` — end-of-session state.
**Files deleted:** None.
@@ -144,7 +144,7 @@ mod tests {
async fn write_text_file_errors_on_bad_parent() {
// Parent dir does not exist → expect Err.
let result = write_text_file_cmd(
"/definitely-not-a-real-path-kon-phase9/out.md".into(),
"/definitely-not-a-real-path-magnotia-phase9/out.md".into(),
"x".into(),
)
.await;
@@ -157,7 +157,7 @@ If `tempfile` is not already a workspace dev-dep, add it to `src-tauri/Cargo.tom
- [ ] **Step 3: Run test to verify it fails**
Run: `cargo test -p kon write_text_file -- --nocapture`
Run: `cargo test -p magnotia write_text_file -- --nocapture`
Expected: FAIL — `write_text_file_cmd` not defined.
- [ ] **Step 4: Add the command**
@@ -177,7 +177,7 @@ pub async fn write_text_file_cmd(path: String, contents: String) -> Result<(), S
- [ ] **Step 5: Tests pass**
Run: `cargo test -p kon write_text_file -- --nocapture`
Run: `cargo test -p magnotia write_text_file -- --nocapture`
Expected: PASS.
- [ ] **Step 6: Commit**
@@ -218,7 +218,7 @@ Add the line inside the block (alphabetical neighbourhood or end — match local
- [ ] **Step 3: Compile**
Run: `cargo build -p kon`
Run: `cargo build -p magnotia`
Expected: clean build.
- [ ] **Step 4: Commit**
@@ -627,7 +627,7 @@ pub use prompts::{ContentTags, INTENT_CLOSED_SET, is_valid_intent};
- [ ] **Step 4: Type-check**
Run: `cargo build -p kon-llm && cargo clippy -p kon-llm -- -D warnings`
Run: `cargo build -p magnotia-llm && cargo clippy -p magnotia-llm -- -D warnings`
Expected: clean.
- [ ] **Step 5: Commit**
@@ -659,10 +659,10 @@ EOF
```rust
// crates/llm/tests/content_tags_smoke.rs
use kon_llm::{extract_content_tags, is_valid_intent, model_manager::LlmModelId};
use magnotia_llm::{extract_content_tags, is_valid_intent, model_manager::LlmModelId};
// Marked #[ignore] so it does not run in default cargo test (the model
// load is heavy). Run explicitly: cargo test -p kon-llm --test
// load is heavy). Run explicitly: cargo test -p magnotia-llm --test
// content_tags_smoke -- --ignored --nocapture.
#[tokio::test]
#[ignore]
@@ -685,14 +685,14 @@ async fn extract_content_tags_on_short_transcript() {
assert!(is_valid_intent(&tags.intent), "intent in closed set: {tags:?}");
}
async fn load_local_tier0_engine() -> Option<kon_llm::LlamaEngine> {
async fn load_local_tier0_engine() -> Option<magnotia_llm::LlamaEngine> {
// Use the existing recommend_tier / model_manager path to find a
// locally-downloaded model file. Skip the test if none is present.
let tier = kon_llm::recommend_tier();
let info = kon_llm::LlmModelInfo::from_id(&LlmModelId::from_tier(tier))?;
let tier = magnotia_llm::recommend_tier();
let info = magnotia_llm::LlmModelInfo::from_id(&LlmModelId::from_tier(tier))?;
let path = info.local_path().ok()?;
if !path.exists() { return None; }
kon_llm::LlamaEngine::load(&path).await.ok()
magnotia_llm::LlamaEngine::load(&path).await.ok()
}
```
@@ -757,9 +757,9 @@ pub async fn extract_content_tags(
- [ ] **Step 3: Build + tests**
```
cargo build -p kon-llm
cargo test -p kon-llm # excludes #[ignore] — should still be green
cargo clippy -p kon-llm -- -D warnings
cargo build -p magnotia-llm
cargo test -p magnotia-llm # excludes #[ignore] — should still be green
cargo clippy -p magnotia-llm -- -D warnings
cargo fmt --check
```
@@ -787,13 +787,13 @@ EOF
### Task 8: `extract_content_tags_cmd` Tauri wrapper
**Files:**
- Modify: the existing LLM-commands file under `src-tauri/src/commands/` (grep for `kon_llm::` to find it; typically something like `llm.rs` or `ai.rs`). If absent, create `src-tauri/src/commands/llm.rs` and register the module in `commands/mod.rs`.
- Modify: the existing LLM-commands file under `src-tauri/src/commands/` (grep for `magnotia_llm::` to find it; typically something like `llm.rs` or `ai.rs`). If absent, create `src-tauri/src/commands/llm.rs` and register the module in `commands/mod.rs`.
- Modify: `src-tauri/src/lib.rs` — register the command.
- [ ] **Step 1: Add the command**
```rust
use kon_llm::{extract_content_tags as llm_extract_content_tags, ContentTags};
use magnotia_llm::{extract_content_tags as llm_extract_content_tags, ContentTags};
// …alongside existing LLM imports.
#[tauri::command]
@@ -827,7 +827,7 @@ In `src-tauri/src/lib.rs` `invoke_handler!`:
- [ ] **Step 3: Build**
Run: `cargo build -p kon && cargo clippy -p kon -- -D warnings && cargo fmt --check`
Run: `cargo build -p magnotia && cargo clippy -p magnotia -- -D warnings && cargo fmt --check`
Expected: clean.
- [ ] **Step 4: Commit**
@@ -837,7 +837,7 @@ git add src-tauri/src/commands/ src-tauri/src/lib.rs
git commit -m "$(cat <<'EOF'
feat(phase9): extract_content_tags_cmd Tauri wrapper
Bridges kon_llm::extract_content_tags to the frontend. Returns a
Bridges magnotia_llm::extract_content_tags to the frontend. Returns a
ContentTags object serialised to the {topic, intent} shape the
frontend stores on item.llmTags.
@@ -1560,7 +1560,7 @@ EOF
### Task 16: Full verification pass + roadmap + HANDOVER
**Files:**
- Modify: `docs/roadmap/2026-04-23-corbie-feature-complete-roadmap.md` — mark Phase 9 shipped.
- Modify: `docs/roadmap/2026-04-23-magnotia-feature-complete-roadmap.md` — mark Phase 9 shipped.
- Modify: `HANDOVER.md` — end-of-session state.
- [ ] **Step 1: Full Rust gate**
@@ -1605,7 +1605,7 @@ Replace the session summary with today's state:
- [ ] **Step 6: Commit**
```bash
git add docs/roadmap/2026-04-23-corbie-feature-complete-roadmap.md HANDOVER.md
git add docs/roadmap/2026-04-23-magnotia-feature-complete-roadmap.md HANDOVER.md
git commit -m "$(cat <<'EOF'
docs(phase9): mark Phase 9 shipped + refresh HANDOVER

View File

@@ -1,12 +1,12 @@
---
name: Phase 8 — Forgiving gamification (design)
description: Design spec for Corbie Phase 8. Surfaces today's completion count and a 7-day momentum sparkline on the Tasks header. No streaks, no grace days, no loss language.
description: Design spec for Magnotia Phase 8. Surfaces today's completion count and a 7-day momentum sparkline on the Tasks header. No streaks, no grace days, no loss language.
type: spec
tags: [spec, phase-8, corbie, tasks, gamification]
tags: [spec, phase-8, magnotia, tasks, gamification]
created: 2026/04/24
status: approved
phase: 8
roadmap: docs/roadmap/2026-04-23-corbie-feature-complete-roadmap.md
roadmap: docs/roadmap/2026-04-23-magnotia-feature-complete-roadmap.md
author: Wren (CORBEL's resident agent) on behalf of Jake Sames
---
@@ -92,7 +92,7 @@ Query groups matching rows by local-day and then left-joins against a generated
// - window focus (for day rollover while the app stayed open overnight)
```
**Why not hook off `kon:task-completed` alone:** that event only fires on completion, not on uncomplete or delete, and relying on it would leave the badge stale after either of those paths. Refreshing at the mutation-helper level captures every path that can change today's count.
**Why not hook off `magnotia:task-completed` alone:** that event only fires on completion, not on uncomplete or delete, and relying on it would leave the badge stale after either of those paths. Refreshing at the mutation-helper level captures every path that can change today's count.
**`src/lib/pages/TasksPage.svelte` header:**
Stacks to:
@@ -150,7 +150,7 @@ Only the sparkline respects the toggle. The badge is always on.
- Migration v13: applies cleanly against a DB populated at v12; default of `auto_completed = 0` on pre-existing rows verified.
### Frontend (`npm run check` + vitest)
- `completionStats` store refreshes on `kon:task-completed` event.
- `completionStats` store refreshes on `magnotia:task-completed` event.
- `todayCount` derives from the last entry.
- Sparkline renders exactly 7 bars for a populated fixture.
- Sparkline hidden when `showMomentumSparkline === false`.

View File

@@ -1,12 +1,12 @@
---
name: Phase 9 — Polish debt (design)
description: Design spec for Corbie Phase 9. Closes six polish-debt items from the feature-complete roadmap plus the Phase 8 carryover backlog. File-system save dialog, bulk History export, on-demand LLM content tags, progressive-disclosure Settings restructure, visual polish, accessibility sweep.
description: Design spec for Magnotia Phase 9. Closes six polish-debt items from the feature-complete roadmap plus the Phase 8 carryover backlog. File-system save dialog, bulk History export, on-demand LLM content tags, progressive-disclosure Settings restructure, visual polish, accessibility sweep.
type: spec
tags: [spec, phase-9, corbie, polish, accessibility, settings, export, llm]
tags: [spec, phase-9, magnotia, polish, accessibility, settings, export, llm]
created: 2026/04/24
status: approved
phase: 9
roadmap: docs/roadmap/2026-04-23-corbie-feature-complete-roadmap.md
roadmap: docs/roadmap/2026-04-23-magnotia-feature-complete-roadmap.md
author: Wren (CORBEL's resident agent) on behalf of Jake Sames
---
@@ -18,7 +18,7 @@ Close the last polish-debt items before Phase 10 (QC + rename + release). Six it
1. **File-system `.md` save dialog** — replaces clipboard-only export on HistoryPage + DictationPage + FilesPage.
2. **Bulk select + bulk export in History** — multi-select rows, export as a directory of `.md` files.
3. **LLM content tags** — on-demand `topic:*` + `intent:*` extraction using `kon-llm`, persisted on history rows.
3. **LLM content tags** — on-demand `topic:*` + `intent:*` extraction using `magnotia-llm`, persisted on history rows.
4. **Settings UX overhaul** — progressive disclosure. High-frequency settings always-visible; advanced behind `<details>` groups. Phase 8 sparkline toggle relocated out of Rituals.
5. **Visual polish pass** — spacing, typography, motion curves, dark-mode parity. Absorbs Phase 8 motion backlog on badge + sparkline.
6. **Accessibility pass** — keyboard navigation, focus order, screen reader labels (friendlier sparkline aria copy), WCAG AA contrast. Absorbs Phase 8 a11y backlog.
@@ -298,9 +298,9 @@ Natural split for the plan: 9a (items 1 + 2), 9b (item 3), 9c (item 4), 9d (item
## Anchors
- Roadmap: [docs/roadmap/2026-04-23-corbie-feature-complete-roadmap.md](../../roadmap/2026-04-23-corbie-feature-complete-roadmap.md)
- Roadmap: [docs/roadmap/2026-04-23-magnotia-feature-complete-roadmap.md](../../roadmap/2026-04-23-magnotia-feature-complete-roadmap.md)
- Phase 8 plan + spec + handover — for task-format reference and carryover backlog.
- Phase 8 gotchas to respect in this phase:
- `$derived` does not export at `.svelte.ts` module scope — use `export function` instead.
- `#[derive(sqlx::FromRow)]` is not available in `kon-storage` (no change in Phase 9, but noted if schema work drifts there).
- `#[derive(sqlx::FromRow)]` is not available in `magnotia-storage` (no change in Phase 9, but noted if schema work drifts there).
- Progressive-disclosure pattern reference: NN/g on progressive disclosure; Material Design settings patterns; UX Collective on settings redesign.