ips/docs/ai/plans/2026-02-25-phase1-code-hygiene-and-architecture.md
Till Wegmueller 9814635a32
feat: Preserve manifest text through install pipeline, add architecture plans
Manifest text is now carried through the solver's ResolvedPkg and written
directly to disk during install, eliminating the redundant re-fetch from
the repository that could silently fail. save_manifest() is now mandatory
(fatal on error) since the .p5m file on disk is the authoritative record
for pkg verify and pkg fix.

Add ADRs for libips API layer (GUI sharing), OpenID Connect auth, and
SQLite catalog as query engine (including normalized installed_actions
table). Add phase plans for code hygiene, client completion, catalog
expansion, and OIDC authentication.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 17:28:10 +01:00

4.7 KiB

Phase 1: Code Hygiene and Architecture Refactoring

Date: 2026-02-25 Status: Active Estimated scope: Foundation work before feature development

Goals

  1. Clean up all dead code, clippy warnings, and formatting issues
  2. Split pkg6 monolithic main.rs into modules
  3. Extract business logic from pkg6 into libips::api
  4. Establish the pattern for GUI-shareable operations

Step 1: Dead Code Cleanup

Remove or annotate all #[allow(dead_code)] items. Rules:

  • Delete if it's legacy/superseded code (e.g., catalog.rs:parse_action)
  • Keep with // WIRED: <plan reference> if it will be used in a known upcoming phase
  • Delete #[allow(unused_imports)] and fix the import
  • Delete #[allow(unused_assignments)] and fix the assignment

Items to address:

File Item Action
libips/src/digest/mod.rs:20 DEFAULT_ALGORITHM Keep — add // WIRED: Phase 2 verify command
libips/src/image/catalog.rs:366 parse_action() Delete — legacy, superseded by SQLite catalog
libips/src/solver/mod.rs:40 PkgCand.id field Remove allow — field is used by resolvo internally
libips/src/repository/file_backend.rs:153,166,329 SearchIndex new(), add_term(), save() Keep — add // WIRED: Phase 2 search index rebuild
libips/src/repository/file_backend.rs:372 Transaction.id Remove allow — expose as pub for logging/debugging
libips/src/repository/obsoleted.rs:768,834 search_entries(), is_empty() Keep — add // WIRED: Phase 2 search and info commands
ports/src/workspace.rs:90,95,100 expand_source_path, get_proto_dir, get_build_dir Evaluate — if ports crate uses them, keep; otherwise delete

TODOs to fix now:

File TODO Action
actions/mod.rs:102,158 mode as bitmask Create FileMode newtype wrapping u32, parse octal string on construction
actions/mod.rs:284 require-any multi-FMRI Leave TODO — Phase 2 solver work
actions/mod.rs:291 dependency_type as enum Create DependencyType enum: Require, Incorporate, Optional, RequireAny, Conditional, Exclude, Group, Parent, Origin
actions/mod.rs:293 root_image as boolean Change to bool, parse "true"/"false" in parser

Step 2: Run clippy and rustfmt

cargo clippy --workspace -- -D warnings 2>&1 | head -100
cargo fmt --all --check

Fix all warnings. Establish CI-level enforcement.

Step 3: Split pkg6/src/main.rs

Create module structure:

pkg6/src/
  main.rs          -- CLI entry point, arg parsing only
  commands/
    mod.rs
    install.rs     -- install + exact-install
    uninstall.rs
    update.rs
    list.rs
    info.rs
    search.rs
    verify.rs
    fix.rs
    history.rs
    contents.rs
    publisher.rs   -- set-publisher, unset-publisher, publisher
    image.rs       -- image-create
    debug.rs       -- debug-db
  output.rs        -- formatting helpers (table, json, tsv)
  error.rs         -- (existing)

Each command module has a single pub async fn run(args: &Args) -> Result<()>.

Step 4: Extract operations into libips::api

Create new API modules:

libips/src/api/
  mod.rs           -- re-exports
  install.rs       -- InstallOptions, install_packages()
  uninstall.rs     -- UninstallOptions, uninstall_packages()
  update.rs        -- UpdateOptions, update_packages()
  search.rs        -- SearchOptions, search_packages()
  info.rs          -- InfoQuery, get_package_info()
  contents.rs      -- get_package_contents()
  verify.rs        -- verify_packages() -> VerificationReport
  progress.rs      -- ProgressReporter trait (shared by CLI/GUI)
  options.rs       -- Common option types

Key trait:

/// Progress reporting for long-running operations.
/// CLI implements with text spinners, GUI with progress bars.
pub trait ProgressReporter: Send + Sync {
    fn on_phase(&self, phase: &str, total: Option<usize>);
    fn on_item(&self, index: usize, name: &str);
    fn on_complete(&self);
    fn on_error(&self, msg: &str);
}

Key options pattern:

pub struct InstallOptions {
    pub dry_run: bool,
    pub accept_licenses: bool,
    pub concurrency: usize,
    pub refresh_before: bool,
    pub additional_repos: Vec<String>,
    pub progress: Option<Arc<dyn ProgressReporter>>,
}

pub fn install_packages(
    image: &mut Image,
    patterns: &[String],
    options: &InstallOptions,
) -> Result<InstallPlan> { ... }

Verification

  • cargo clippy --workspace -- -D warnings passes clean
  • cargo fmt --all --check passes clean
  • cargo nextest run passes (excluding known slow tests)
  • No #[allow(dead_code)] without // WIRED: annotation
  • pkg6 commands still work identically after refactor