Skip to content

feat(app): implement AppConfig for filesystem layout resolution#19

Merged
mpiton merged 3 commits intomainfrom
feat/task-T-103-app-config
May 4, 2026
Merged

feat(app): implement AppConfig for filesystem layout resolution#19
mpiton merged 3 commits intomainfrom
feat/task-T-103-app-config

Conversation

@mpiton
Copy link
Copy Markdown
Owner

@mpiton mpiton commented May 4, 2026

Summary

Implements AppConfig struct + boot-time path resolution (T-103). Resolves Forgent's filesystem layout once at startup — per-project paths (<root>/.claude/forgent/{tasks.db,prompts/}) + per-user paths (~/.forgent/{logs,cache}). Supports env override FORGENT_PROJECT_ROOT with CWD fallback.

This PR is part of Sprint 1 backend foundations and stacks on T-102 (AppError types). Both are required for AppContainer::build (T-116).

Why

Path resolution must happen once at boot before any I/O operations. Centralizing this in AppConfig ensures consistent layout across the codebase and enables testability (configs built with explicit paths rather than env vars during tests).

Changes

T-102 (included as prerequisite):

  • Added AppError + DomainError error types (thiserror + serde for IPC boundary)

T-103 (primary):

  • Added src-tauri/src/config.rs with AppConfig struct (5 PathBuf fields: project_root, db_path, logs_dir, cache_dir, prompts_overrides_dir)
  • AppConfig::load() — production entry point, reads env then CWD
  • AppConfig::new(project_root) — testable constructor with validation
  • resolve_project_root() — env FORGENT_PROJECT_ROOT override → CWD fallback
  • Validates project_root.is_dir() else AppError::Invalid
  • Uses dirs::home_dir() for cross-platform per-user paths (Linux XDG / macOS NSHome / Windows USERPROFILE)
  • 6 unit tests via tempfile + temp-env (safe env mutation without unsafe)
  • Added dev-deps: tempfile, temp-env

Follow-up cleanup (/simplify):

  • Stripped doc-comment task references (CLAUDE.md compliance)
  • Deduplicated 2 redundant tests (8 → 6 tests, identical coverage)
  • Reused existing From<std::io::Error> impl via .map_err(Into::into)

Testing

Cargo test suite — 23 tests across 4 suites pass:

cargo test --workspace
cargo clippy --workspace --all-targets -- -D warnings  # clean
cargo fmt --check                                       # clean
cargo deny check                                        # clean (advisories/licenses)

Specific config tests:

  • new_returns_ok_for_valid_tempdir — valid temp dir accepted
  • new_rejects_non_existent_project_root — missing dir rejected with AppError::Invalid
  • new_rejects_file_instead_of_directory — file path rejected
  • resolve_project_root_honors_env_overrideFORGENT_PROJECT_ROOT env var used
  • resolve_project_root_falls_back_to_cwd_when_env_unset — CWD fallback
  • app_config_is_send_sync_clone — trait bounds verified

Related Issues

  • Task T-103: Create AppConfig::load
  • Task T-102: Create AppError + DomainError (prerequisite, stacked in this PR)

Notes for Reviewer

This is a stacked PR containing both T-102 and T-103 commits. T-102 (feat(domain): add AppError + DomainError) should ideally be reviewed/merged as a separate PR first, but both are included here due to the branch dependency. If preferred, they can be split — T-102 commits can land separately, then T-103 rebased.

The key validation point: AppConfig::new validates project_root.is_dir() at boot time for fast-fail diagnostics, not as a TOCTOU security boundary (the real use — libsql/ensure_dirs — happen afterward and handle errors independently).

Checklist

  • Tests added/updated and passing locally (cargo test --workspace)
  • Docs updated (CHANGELOG.md, module doc)
  • No secrets, debug prints, or commented-out code
  • Self-reviewed the diff
  • Clippy + fmt green

Summary by CodeRabbit

  • New Features

    • New configuration system that automatically detects project root and manages application paths for databases, logs, and cache.
    • Improved error handling with structured error types for better diagnostics.
  • Documentation

    • Updated changelog documenting configuration and error handling improvements.
  • Chores

    • Added development dependencies for enhanced testing capabilities.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 4, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: bbb0dda2-b868-45a8-a703-c96de2d26937

📥 Commits

Reviewing files that changed from the base of the PR and between 1561f47 and 8537a1a.

⛔ Files ignored due to path filters (1)
  • src-tauri/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (4)
  • CHANGELOG.md
  • src-tauri/Cargo.toml
  • src-tauri/src/config.rs
  • src-tauri/src/lib.rs
✅ Files skipped from review due to trivial changes (3)
  • src-tauri/Cargo.toml
  • src-tauri/src/config.rs
  • CHANGELOG.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • src-tauri/src/lib.rs

📝 Walkthrough

Walkthrough

A new AppConfig struct is introduced in a dedicated module to centralize filesystem path resolution and validation. The module is wired into the public API via lib.rs re-exports. Dev test dependencies are added to support validation. Changes are documented in the changelog.

Changes

Configuration Module & Public API

Layer / File(s) Summary
Dev Dependencies
src-tauri/Cargo.toml
Added temp-env and tempfile dev dependencies to support testing of configuration path logic and environment variable overrides.
Core Configuration
src-tauri/src/config.rs
Introduces AppConfig struct with project_root, db_path, logs_dir, cache_dir, and prompts_overrides_dir fields. Implements AppConfig::load() and AppConfig::new() for initialization and validation; resolve_project_root() reads FORGENT_PROJECT_ROOT env var or falls back to current directory.
Path Validation Tests
src-tauri/src/config.rs
Unit tests validate directory existence, env override behavior, UTF-8 handling on Unix, and compile-time trait bounds (Send + Sync + Clone).
Public API Wiring
src-tauri/src/lib.rs
Declares pub mod config and re-exports AppConfig and AppError at crate root for IPC exposure.
Documentation
CHANGELOG.md
Records configuration module addition, AppConfig export surface, and related AppError/DomainError IPC boundary changes.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

Poem

🐰 A config comes to light so bright,
With paths resolved and validated right,
Env vars dance, home dirs align,
The public face now takes its sign!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main feature being introduced: AppConfig and filesystem layout resolution. It is concise, clear, and directly reflects the primary changes shown in the PR (new config.rs with AppConfig struct and path resolution logic).
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/task-T-103-app-config

Review rate limit: 3/5 reviews remaining, refill in 18 minutes and 58 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@CHANGELOG.md`:
- Line 14: Update the changelog bullet that documents tests for AppConfig to
reflect the actual test count: change the “8 tests” mention to “6 tests” so it
matches the final test module in src-tauri/src/config.rs (the AppConfig test
module) and the note on Line [9] that already documents the 8→6 dedupe; ensure
the sentence still references AppConfig, resolve_project_root(),
AppConfig::load()/AppConfig::new(), and the use of tempfile + temp-env.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: acfd9557-a492-473c-9f01-3afaf0a0e2da

📥 Commits

Reviewing files that changed from the base of the PR and between b2d551e and ce58bdc.

⛔ Files ignored due to path filters (1)
  • src-tauri/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (6)
  • CHANGELOG.md
  • src-tauri/Cargo.toml
  • src-tauri/src/config.rs
  • src-tauri/src/domain/shared/error.rs
  • src-tauri/src/error.rs
  • src-tauri/src/lib.rs

Comment thread CHANGELOG.md Outdated
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 7 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src-tauri/src/config.rs">

<violation number="1" location="src-tauri/src/config.rs:42">
P2: Do not swallow non-UTF8 `FORGENT_PROJECT_ROOT` values as if the variable were unset; handle `NotPresent` and `NotUnicode` separately so invalid config fails explicitly.</violation>
</file>

<file name="CHANGELOG.md">

<violation number="1" location="CHANGELOG.md:14">
P3: Update the `AppConfig` changelog bullet to reflect the current test count; it currently contradicts the new simplification note (6 tests vs 8 tests).</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread src-tauri/src/config.rs Outdated
Comment thread CHANGELOG.md Outdated
mpiton added a commit that referenced this pull request May 4, 2026
Address PR #19 review:

- cubic-dev-ai @ config.rs:42 — `std::env::var()` returns
  `Err(VarError::NotUnicode(_))` when the env var is set but contains
  non-UTF-8 bytes (legal on Unix filesystems). The old `Err(_)` arm
  silently fell back to CWD, swallowing user-set config. Switched to
  `std::env::var_os()` which returns the raw `OsString`, so explicit
  signal is preserved and non-UTF-8 paths work natively. Added
  `#[cfg(unix)]` regression test using `OsStringExt::from_vec` with
  `0xFF 0xFE` bytes.
- coderabbitai + cubic-dev-ai @ CHANGELOG.md:14 — bullet said "8 tests"
  but the simplify pass deduped to 6 and this commit adds the non-UTF-8
  test → 7. Updated the count.
mpiton added 3 commits May 4, 2026 14:35
…sk T-103)

`AppConfig` resolves Forgent's filesystem layout once at boot (PRD §0.3):
- per-project: `<root>/.claude/forgent/{tasks.db,prompts/}`
- per-user:    `~/.forgent/{logs,cache}` via `dirs::home_dir()`

Three entry points:
- `AppConfig::load()` — reads env then CWD (production path)
- `AppConfig::new(project_root)` — validates + builds (testable directly)
- `resolve_project_root()` — `FORGENT_PROJECT_ROOT` env override → CWD fallback

Validates `project_root.is_dir()` else `AppError::Invalid`. Will be consumed
by `filesystem::paths::ensure_dirs` (T-104), tracing (T-105), libsql (T-106),
and `AppContainer::build` (T-116).

Tests use `tempfile` + `temp-env` (encapsulates `unsafe` env mutation that
Rust 2024 edition would otherwise force — CLAUDE.md forbids `unsafe` outside
ADRs). 8 unit tests, all green.

One deviation from the T-103 task spec, documented in CHANGELOG:
`AppConfig::load(app_handle: &tauri::AppHandle)` → `AppConfig::load()`. The
illustrative `AppHandle` param was never used in the body — per-user paths
come from `dirs::home_dir()`, not `app.path()`. Keeping it would force a
`tauri::test::MockRuntime` harness for zero functional gain.

Refs: T-103, ARCHI.md §5.5, PRD §0.3
…tests, reuse io::Error From impl

- Module doc 9 → 1 line; removed T-104/T-105/T-106/T-116 task references
  (CLAUDE.md "no task references in comments").
- `resolve_project_root` uses existing `From<std::io::Error>` via `.map_err(Into::into)`
  (the impl already lives in `error.rs`; hand-rolled `AppError::Io(e.to_string())`
  was redundant).
- Deleted `paths_use_pathbuf_join_cross_platform` — covered by
  `new_returns_ok_for_valid_tempdir`.
- Deleted `load_with_env_override_to_tempdir_succeeds` — `load()` is just
  `Self::new(resolve_project_root()?)`, both legs independently tested.

8 → 6 tests, identical coverage; cargo test --workspace 23 → 21 (4 suites green).
Address PR #19 review:

- cubic-dev-ai @ config.rs:42 — `std::env::var()` returns
  `Err(VarError::NotUnicode(_))` when the env var is set but contains
  non-UTF-8 bytes (legal on Unix filesystems). The old `Err(_)` arm
  silently fell back to CWD, swallowing user-set config. Switched to
  `std::env::var_os()` which returns the raw `OsString`, so explicit
  signal is preserved and non-UTF-8 paths work natively. Added
  `#[cfg(unix)]` regression test using `OsStringExt::from_vec` with
  `0xFF 0xFE` bytes.
- coderabbitai + cubic-dev-ai @ CHANGELOG.md:14 — bullet said "8 tests"
  but the simplify pass deduped to 6 and this commit adds the non-UTF-8
  test → 7. Updated the count.
@mpiton mpiton force-pushed the feat/task-T-103-app-config branch from 1561f47 to 8537a1a Compare May 4, 2026 12:36
@codspeed-hq
Copy link
Copy Markdown
Contributor

codspeed-hq Bot commented May 4, 2026

Merging this PR will not alter performance

✅ 7 untouched benchmarks


Comparing feat/task-T-103-app-config (8537a1a) with main (b2d551e)

Open in CodSpeed

@mpiton mpiton merged commit ccb4870 into main May 4, 2026
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant