Introduces the architectural spine for the Wyrdnote engine layer per
the spec at outputs/wyrdnote/2026-05-10-engine-architecture-spec.md
in the CORBEL-Main workspace, Codex-reviewed 2026/05/10.
Clean-room derivative of VoiceInk's TranscriptionService /
TranscriptionServiceRegistry / TranscriptionPipeline shape. Built from
the architectural pattern only; no GPL-3.0 code, comments, or
identifiers lifted. Wyrdnote names, control flow, and trait signatures
are original.
What this lands:
crates/cloud-providers/src/provider.rs (new, 184 lines)
TranscriptionProvider async trait. Object-safe via async_trait so
Arc<dyn TranscriptionProvider> is the canonical shape. Lives in
cloud-providers (not transcription) per D7 so an OEM licensee
implementing the trait depends only on this crate plus magnotia-core
(no transcription internals leaked through the trait surface).
Surrounding types: ProviderId (lower-kebab-case), ProviderKind,
NetworkRequirement, CostClass, ProviderCapabilities, EngineProfile,
ProviderTranscript. Compile-time object-safety witness in tests.
crates/cloud-providers/Cargo.toml (modified)
Adds async-trait + serde dependencies.
crates/cloud-providers/src/lib.rs (modified)
Re-exports the provider surface.
crates/transcription/src/registry.rs (new, 183 lines)
EngineRegistry: catalogue of providers keyed by ProviderId. Push-style
registration, default-provider id captured at construction. Read-only
after boot. Full unit-test coverage: empty default, register/get
round-trip, default-resolves-after-registration, re-register replaces,
ids enumeration.
crates/transcription/src/orchestrator.rs (new, 286 lines)
LocalProviderAdapter wraps Arc<LocalEngine>, presents async
TranscriptionProvider upward via tokio::task::spawn_blocking. Per D7
the adapter lives in the orchestrator, NOT as impl TranscriptionProvider
for LocalEngine — this keeps the dependency edge one-directional and
avoids leaking async-runtime requirements onto the synchronous
Transcriber trait.
Orchestrator: single transcribe() entry point; resolves a provider
from the registry, derives TranscriptionOptions from the EngineProfile,
dispatches. Returns a clear error when an unregistered provider is
named. Unit tests use a mock CannedProvider to validate dispatch,
error handling, and option routing without booting a real model.
crates/transcription/Cargo.toml (modified)
Depends on magnotia-cloud-providers + async-trait. Dev-dep tokio
gains macros + rt-multi-thread features for #[tokio::test].
crates/transcription/src/lib.rs (modified)
Exports Orchestrator, EngineRegistry, LocalProviderAdapter, and
re-exports the provider trait surface so downstream crates depend
only on magnotia-transcription for both local engines and the trait.
KNOWN-ISSUES.md (modified)
Adds KI-06: existing dictation, live, and meeting commands still call
LocalEngine::transcribe_sync directly via pick_engine. The orchestrator
path is dormant until a Phase A.1 follow-up commit migrates the call
sites. Cloud providers (Phase G) cannot be exercised end-to-end until
the rewire lands. Phasing rationale: this commit lands the abstractions
cleanly with full test coverage; the rewire is a separate diff so the
chunking + post-processing logic in transcribe_file moves without
inflating this commit beyond review fidelity.
Test results: 9 new tests pass (orchestrator: dispatches, errors-on-
unregistered, routes-initial-prompt, object-safe; registry: empty-default,
round-trip, default-resolves, re-register, ids-list). Pre-existing
59 transcription tests + 5 cloud-providers tests still green.
cargo check --workspace clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Run with:
cargo run -p magnotia-core --example tuning_log_demo
Initialises a tracing-subscriber fmt layer so the inference_thread_count
INFO event is rendered to stderr. Exercises all 8 (workload,
gpu_offloaded) combos under three power scenarios: AC override,
battery override, and the real sysfs probe.
Used to validate the heuristic on 2026-05-09 against the spec's
6c12t truth table — all 6 rows match.
Adds tracing-subscriber as a [dev-dependencies] for the example.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wires the whisper backend through the new tuning helper. gpu_offloaded
combines a compile-time feature check (whisper-vulkan, in default
features) with a runtime libvulkan probe via the hardware module. If
libvulkan1 is missing on Linux, whisper-rs's vulkan backend silently
falls back to CPU, so we should not reduce threads in that case.
The old magnotia_core::constants::inference_thread_count import is
replaced by tuning::{inference_thread_count, Workload}. The constants
module's helper is removed in Task 6.1 once the LLM call site has
also migrated.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Introduces crates/core/src/power.rs with the PowerState enum
(OnAc / OnBattery / Unknown) and a unit test confirming the three
variants are distinct. Registers the module in lib.rs and adds
tempfile = "3" to dev-dependencies for use in later tasks.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.
Adds llm_tags TEXT NOT NULL DEFAULT '' to the transcripts table via
new migration v14. SELECT statements + TranscriptRow + transcript_row_from
now carry the column. update_transcript_meta gains a sixth Option for
llm_tags following the existing COALESCE pattern; an
#[allow(too_many_arguments)] keeps clippy happy without inverting the
signature into a struct that would just shift the indirection.
The Tauri-side TranscriptDto + UpdateTranscriptMetaRequest + the
update_transcript_meta_cmd command pass llm_tags through unchanged.
Pre-existing manualTags persistence path now has a sibling for
llmTags ready for the frontend to call.
Phase 8 brittle test fix included: list_recent_completions_uses_local_day_boundary
was anchoring its "-2 days" UTC offset against the local-day spine,
which drifted across UTC midnight. Anchored to the local date directly
so it matches the spine regardless of clock.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Downstream effect of the Task 4 commit (83bd338) adding
serde = "1" to crates/storage/Cargo.toml. Lockfile change is a
single line recording the new dependency on the pinned crates.io
version; no other crates affected.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Frontend-owned nudge bus that consumes in-app signals Corbie already
produces, applies suppression, and fans out to OS notification + an
optional TTS read-aloud. OS-wide keyboard/window activity detection
stays deferred per the revised roadmap — the plan before rewrite
would have been brittle on Wayland, permission-heavy on macOS, and
low-quality everywhere.
Triggers (v1, all in-app signals):
- inactivity_with_active_timer — timer running, window blurred ≥ 90 s,
at least 60 s into the timer.
- pending_morning_triage — ritual enabled, past 10:00 local, last
shown ≠ today. Polls every 5 min while focused.
- micro_step_idle — micro-step decomposition created, no child step
or parent task completed within 15 min.
Suppression:
- Respects nudgesEnabled + nudgesMuted.
- No nudge while the app has focus (document.hasFocus).
- Hard cap 3 per rolling hour.
- Permission requested via @tauri-apps/plugin-notification on first
delivery; denial is silently respected.
Rust side:
- tauri-plugin-notification registered + ACL entries on the main-
window capability only (secondary windows can't fire nudges).
- commands::nudges::deliver_nudge — thin wrapper, security-guarded
via ensure_main_window, delegates to the plugin. No DB writes —
the roadmap's nudges-audit table is deferred until a concrete need
emerges.
Frontend glue:
- nudgeBus.svelte.ts — subscribes to window events, applies
suppression, calls deliver_nudge (+ tts_speak when speakAloud is
on).
- kon:task-completed now dispatched on complete_task_cmd success.
- kon:microstep-generated + kon:step-completed dispatched from
MicroSteps so the idle trigger can clear itself on any engagement.
- kon:focus-timer-cancelled added to focusTimer so the bus can reset
its inactivity state on cancel, not only on natural completion.
- nudgeBus started from +layout.svelte onMount, stopped on destroy.
Settings:
- New "Nudges" section with three toggles: Enable nudges, Mute for
now (separate so a hard mute doesn't lose preferences),
Speak nudges aloud (reuses Phase 4 TTS).
- All default OFF. No first-run prompt — nudges are a Settings-found
feature rather than a walkthrough step.
Out of scope per the revised Phase 6 spec: OS-wide keyboard/window
hooks, biometric signals, custom trigger editor (Phase 7), notification
sound (platform variance too high for Layer-1 — revisit in Phase 9
polish with a bundled .wav).
Gates: fmt clean, clippy -D warnings clean, cargo test 262/0 (4
existing + 262 current), npm run check 0/0, npm run build green.