Files
loki/docs/implementation/PHASE-1-STEP-16-NOTES.md

3.7 KiB

Phase 1 Step 16 Notes: Config → AppConfig Migration Cleanup

Date: 2026-04-19 Status: PENDING (cleanup task)

Overview

Complete the migration of mutations from Config to AppConfig/AppState so that Config becomes a pure POJO (serde serialization/deserialization only).

Problem

The current startup flow mutates Config during init, then calls to_app_config() which only copies serialized fields, losing all the runtime mutations:

YAML → Config (mutated during init)
    ↓
cfg.to_app_config()  ← COPIES ONLY, loses mutations

Mutations happening in Config::init

These methods mutate Config and should be migrated to AppConfig:

Method Location What It Does
load_envs() mod.rs:387 Env var overrides into Config fields
set_wrap(&wrap)? mod.rs:390 Parse wrap string into Config.wrap
load_functions() mod.rs:393 Load tool functions into Config.functions
setup_model() mod.rs:398 Resolve model name → Model
load_mcp_servers() mod.rs:395 Start MCP servers into Config.mcp_registry
setup_document_loaders() mod.rs:399 Load document loaders
setup_user_agent() mod.rs:400 Set user_agent to "auto"

Other Config Methods Still In Use

Method Location Used By
set_model(&model_id) mod.rs:457-466 Runtime (role-like mutators)
vault_password_file() mod.rs:411-419 vault/mod.rs:40
sessions_dir() mod.rs:421-429 Session management
role_like_mut() mod.rs:431-441 Role/session/agent mutation
set_wrap(&str) mod.rs:443-455 Runtime wrap setting

Solution

Option A (Quick): Move mutations after the bridge in main.rs:

// main.rs
let cfg = Config::init(...).await?;
let app_config = Arc::new(cfg.to_app_config());  // Step 1: copy serialized

// Step 2: apply mutations to AppConfig
app_config.load_envs();
app_config.set_wrap(&wrap)?;
app_config.setup_model()?;  // May need refactored

// Step 3: build AppState
let app_state = Arc::new(AppState {
    config: app_config,
    vault: cfg.vault.clone(),
    // ... other fields
});

// Step 4: build RequestContext (runtime only, no config logic)
let ctx = cfg.to_request_context(app_state);

Option B (Proper): Remove Config entirely from startup flow - build AppConfig directly from YAML.

Duplicated Code to Clean Up

After migration, these duplicated methods can be removed from AppConfig:

Duplicated Config Location AppConfig Location
load_envs() mod.rs:582-722 app_config.rs:283-427
set_wrap() mod.rs:443-455 app_config.rs:247-259
setup_document_loaders() mod.rs:782-789 app_config.rs:262-269
setup_user_agent() mod.rs:791-799 app_config.rs:272-280
Default impls mod.rs:232-311 app_config.rs:94-149

Target State

After Step 16:

  • Config only has serde fields + Deserialization (no init logic)
  • AppConfig receives all runtime mutations
  • AppState built from AppConfig + Vault
  • RequestContext built from AppState + runtime state
  • Duplicated methods removed from AppConfig (or retained if needed)
  • Bridge simplified to just field copying

Files to Modify

  • src/config/mod.rs - Remove init mutations, keep only serde
  • src/config/app_config.rs - Enable mutations, remove duplication
  • src/main.rs - Move bridge after mutations
  • src/config/bridge.rs - Simplify or remove

Notes

  • This cleanup enables proper REST API behavior
  • Each HTTP request should build fresh RequestContext from AppConfig
  • AppConfig should reflect actual runtime configuration