Files
Lumotia/crates/storage/Cargo.toml
Jake 52565ea8b8 agent: area A commit 1 — typed magnotia_storage::Error + boundary
Commit 1 of 2 for engine-slop residuals Area A.

Adds a typed `magnotia_storage::Error` enum and rewires every error
construction site in the storage crate to use it. The crate boundary
into `magnotia_core::error::MagnotiaError` is handled by a
`From<storage::Error> for MagnotiaError` impl that lives inside the
storage crate (not in core) to avoid a `core -> storage` dependency
cycle. The old `MagnotiaError::StorageError(String)` variant is kept
in this commit as an unused placeholder; commit 2 deletes it.

New types in crates/storage/src/error.rs:
- pub enum Error { DatabaseOpen, Migration, Query, NotFound,
  InvalidReference, Filesystem } with #[derive(thiserror::Error)]
- pub enum OpenOp { Connect, ReadOnlyConnect, ForeignKeysPragma }
- pub enum MigrationStep { SchemaVersionTableCreate, SchemaVersionQuery,
  TxBegin, Apply, RecordVersion, Commit }
- pub enum Entity { Transcript, Task, Profile, ImplementationRule,
  Feedback } — seeded only with entities that have a real
  NotFound/InvalidReference case in the codebase
- pub type Result<T> = std::result::Result<T, Error>
- impl Error { pub fn kind() -> StorageKind, pub fn
  operation_label() -> Cow<'static, str> }
- impl From<Error> for MagnotiaError

New types in crates/core/src/error.rs:
- MagnotiaError::Storage { kind: StorageKind, operation: String,
  detail: String } with #[error("{detail}")] so the boundary doesn't
  double-prefix Display output
- pub enum StorageKind { DatabaseOpen, Migration, Query, NotFound,
  InvalidReference, Filesystem } #[derive(Serialize)]
  #[serde(rename_all = "snake_case")] for future Area E

Storage crate dependency added: thiserror = "1"

Migration scope:
- migrations.rs: 6 sites → Error::Migration with structured step + version
- database.rs: 72 sites broken down as:
  * 3  → Error::DatabaseOpen (init / readonly / pragma)
  * 1  → Error::Filesystem (init's create_dir_all with path context)
  * ~58 → Error::Query with operation labels matching the prior message
        stem in snake_case; transaction sub-steps use dotted labels
        ("complete_subtask_and_check_parent.commit_transaction" etc.)
        so transaction internals are not collapsed
  * 5  → Error::NotFound (transcript / task×2 / implementation_rule×2)
  * 5  → Error::InvalidReference (insert_transcript unknown profile;
        Default profile rename/delete invariants ×3; feedback rating
        value validation)

Survey ambiguities resolved per the locked answers:
- Q1 (schema_version_query): Migration step, not Query
- Q2 (transaction sub-steps): preserved granularity with dotted operation
  labels; no collapsing
- Q3 (Entity cardinality): seeded with the 3 from the survey + 2 more
  discovered during migration (ImplementationRule, Feedback), per
  "add when an actual case needs it"
- Q4 (operation label type): Cow<'static, str>
- Q5 (Serialize): storage::Error is not serializable; flattens only at
  the MagnotiaError boundary
- Q6 (re-exports): pub use error::{Entity, Error, MigrationStep, OpenOp,
  Result} in storage::lib.rs; StorageKind belongs to magnotia_core

Two scope-discovered additions beyond the original 5 variants:
- Error::Filesystem { path, source } variant + matching StorageKind —
  required because init() now returns storage::Result<SqlitePool> and
  the create_dir_all call needs a typed path; doing this via
  From<io::Error> for storage::Error would have lost the path so it's
  explicit
- Entity::ImplementationRule and Entity::Feedback — two NotFound /
  InvalidReference sites the original survey missed in the rule-CRUD
  and feedback-validation areas

Verification:
- cargo fmt --all
- cargo check --workspace --all-targets — clean
- cargo test -p magnotia-storage — 60 passed, 0 failed
- cargo test --workspace — all green, ~330 tests
- rg 'StorageError\(' crates/ src-tauri/src/ — only hit is the variant
  declaration in core that commit 2 will delete
- rg 'Other\(String' crates/storage/src/ — zero
- rg 'format!\("[A-Z].* failed' crates/storage/src/ — zero

Commit 2 will delete MagnotiaError::StorageError(String) once this is
in. Pre-existing working-tree churn in crates/llm/, src/lib/pages/,
src/lib/utils/saveMarkdown.ts and the untracked phase10a dogfood notes
deliberately left unstaged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 22:57:17 +01:00

32 lines
1.1 KiB
TOML

[package]
name = "magnotia-storage"
version = "0.1.0"
edition = "2021"
description = "SQLite persistence, BM25 search, and file storage for Magnotia"
[dependencies]
magnotia-core = { path = "../core" }
# SQLite with compile-time checked queries
# default-features = false strips sqlx's `any`, `macros`, `migrate`, `json` —
# none of which this crate uses (it calls sqlx::query() / query_scalar()
# directly and runs its own migration machinery). Cuts ~40% of sqlx's
# compile graph, most visibly on Windows MSVC where each proc-macro crate
# (which `macros` pulls in) becomes a slow .dll link.
sqlx = { version = "0.8", default-features = false, features = ["runtime-tokio", "sqlite"] }
# Async runtime
tokio = { version = "1", features = ["rt", "sync", "macros"] }
# Serialisation (DailyCompletionCount exposed to frontend via Tauri commands)
serde = { version = "1", features = ["derive"] }
# Logging
log = "0.4"
# Structured error derivation for magnotia_storage::Error.
thiserror = "1"
# UUIDs for profile + profile_terms ids (v7 random).
uuid = { version = "1", features = ["v4"] }