# Modular Development Workflow and Traceability Goal - Enable incremental implementation without re-reading the entire codebase each time. - Make module changes discoverable via grep and predictable locations. - Keep a single source of truth for the API surface, invariants, and extension points. Core Principles 1) Contract-first per module - API signatures and responsibilities are documented in [docs/API-SKELETONS.md](docs/API-SKELETONS.md) and mirrored by crate modules: - [src/types.rs](src/types.rs) - [fn load_and_merge()](src/config/loader.rs:1), [fn validate()](src/config/loader.rs:1) - [fn from_args()](src/cli/args.rs:1) - [struct LogOptions](src/logging/mod.rs:1), [fn init_logging()](src/logging/mod.rs:1) - [fn discover()](src/device/discovery.rs:1) - [fn plan_partitions()](src/partition/plan.rs:1), [fn apply_partitions()](src/partition/plan.rs:1) - [fn plan_filesystems()](src/fs/plan.rs:1), [fn make_filesystems()](src/fs/plan.rs:1) - [fn plan_mounts()](src/mount/ops.rs:1), [fn apply_mounts()](src/mount/ops.rs:1), [fn maybe_write_fstab()](src/mount/ops.rs:1) - [const REPORT_VERSION](src/report/state.rs:1), [fn build_report()](src/report/state.rs:1), [fn write_report()](src/report/state.rs:1) - [struct Context](src/orchestrator/run.rs:1), [fn run()](src/orchestrator/run.rs:1) - [fn detect_existing_state()](src/idempotency/mod.rs:1), [fn is_empty_disk()](src/idempotency/mod.rs:1) - [struct CmdOutput](src/util/mod.rs:1), [fn which_tool()](src/util/mod.rs:1), [fn run_cmd()](src/util/mod.rs:1), [fn run_cmd_capture()](src/util/mod.rs:1), [fn udev_settle()](src/util/mod.rs:1) 2) Grep-able region markers in code - Every module contains the following optional annotated regions: - // REGION: API - // REGION: EXTENSION_POINTS - // REGION: SAFETY - // REGION: ERROR_MAPPING - // REGION: TODO - Example snippet to add near top of a module: // REGION: API // api: device::discover(filter: &DeviceFilter) -> Result> // api: device::DeviceProvider // REGION: API-END - These must be kept concise, one-liners per function/trait/struct; they act as a quick index for search. 3) Stable identifiers for cross-references - Use short identifiers in comments to reference public items: - api: module::item - ext: module::hook_or_trait - safety: module::invariant_name - errmap: module::error_path - This allows quick discovery via regex: grep -R "api: device::" src/ 4) Single source of truth for API surface - Keep high-level API in [docs/API-SKELETONS.md](docs/API-SKELETONS.md) as canonical index. After adding/removing a public function or type, update this file. - Add a short note in [docs/SPECS.md](docs/SPECS.md) if behavior or invariants change. 5) Architectural decisions recorded as ADRs - Use docs/adr/NNNN-title.md to document decisions (context, decision, consequences). - Start with [docs/adr/0001-modular-workflow.md](docs/adr/0001-modular-workflow.md) (added alongside this doc). - Link ADRs from [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) when they supersede or refine prior guidance. 6) Module ownership and boundaries - Add a “Module Responsibilities” section in each module’s header doc comment summarizing scope and non-goals. - Example references: - [src/device/discovery.rs](src/device/discovery.rs) - [src/partition/plan.rs](src/partition/plan.rs) - [src/fs/plan.rs](src/fs/plan.rs) - [src/mount/ops.rs](src/mount/ops.rs) - [src/report/state.rs](src/report/state.rs) 7) Invariants and safety notes - For code that must uphold safety or idempotency invariants, annotate with: // SAFETY: explanation // IDEMPOTENCY: explanation - Example locations: - [fn apply_partitions()](src/partition/plan.rs:1) must enforce empty-disks rule when configured. - [fn make_filesystems()](src/fs/plan.rs:1) must not run if partitioning failed. 8) Error mapping consistency - Centralize conversions to [enum Error](src/errors.rs:1). When calling external tools, wrap failures into Error::Tool with stderr captured. - Annotate mapping areas with: // ERROR: mapping external failure to Error::Tool 9) Module-local CHANGELOG entries - Keep a single CHANGELOG in the repo root, plus module-local “Changes” sections appended on each module top comment (short bullets). - Cross-link to the ADR when relevant. 10) Task-level breadcrumbs - For multi-step features, add a short progress marker at top of relevant modules: // TODO(KILO): feature-X step 2/4 – parsing args done; next implement validation - Summary of active tasks can also live in docs/SPECS.md under “In-Progress Work”. 11) Example configs and fixtures - Keep comprehensive examples in: - [config/zosstorage.example.yaml](config/zosstorage.example.yaml) - Add minimal example variants if needed for tests (future): - examples/config/minimal.yaml - examples/config/dual-btrfs.yaml - examples/config/ssd-hdd-bcachefs.yaml 12) “Golden paths” for resuming work - If resuming work later: - Read module headers for responsibilities - Grep for REGION markers: API / TODO / SAFETY / ERROR_MAPPING - Check [docs/API-SKELETONS.md](docs/API-SKELETONS.md) for contract changes - Check latest ADRs in docs/adr/ - Check [docs/SPECS.md](docs/SPECS.md) and the “In-Progress Work” section (if used) Checklist for adding a new feature - Update contracts: - Add or modify function/type signatures in code and reflect in [docs/API-SKELETONS.md](docs/API-SKELETONS.md) - Add REGION: API one-liners for the new items - Update invariants: - Add REGION: SAFETY notes if needed - Update specs: - Document behavior in [docs/SPECS.md](docs/SPECS.md) - If it is a long-term decision, add an ADR under docs/adr/ - Add examples if config or output formats change - Update [config/zosstorage.example.yaml](config/zosstorage.example.yaml) or add a new example file - Keep error mapping and logging consistent: - Ensure any external tool calls map errors to [enum Error](src/errors.rs:1) - Run cargo build and update any broken references Optional automation (future) - A simple “index check” script (cargo xtask) could validate: - All public items referenced under REGION: API appear in [docs/API-SKELETONS.md](docs/API-SKELETONS.md) - No broken module references - REGION markers are well-formed By following these conventions, changes stay localized and discoverable. A contributor (human or assistant) can quickly locate relevant areas by scanning module headers, REGION markers, and the centralized API/docs without re-reading the entire tree.