Skip to content

RFC-003: Generate Command Decomposition Plan (Q1 2026)

  • Status: Completed (G1-G6 merged)
  • Date: 2026-02-09
  • Owner: DX/Core
  • Scope: crates/assay-cli/src/cli/commands/generate.rs
  • Related:
  • docs/architecture/RFC-002-code-health-remediation-q1-2026.md (E5)
  • docs/architecture/CODE-ANALYSIS-REPORT.md (#27)

0. Status Evidence (mechanical)

Item Status Reference Merge SHA Date
G1 Merged PR #260 99588b59 2026-02-09
G2 Merged PR #262 545fcd09 2026-02-09
G3 Merged PR #264 059e23d2 2026-02-09
G4 Merged PR #266 a661b911 2026-02-09
G5 Merged PR #268 b3d386bf 2026-02-09
G6 Merged PR #271 f21c85ef 2026-02-09
Generate validate finite checks Merged PR #270 7cc96a8a 2026-02-10

1. Context

generate.rs is currently ~1166 lines and combines multiple concerns:

  1. CLI argument model and validation
  2. Policy/output DTOs and serialization
  3. Trace ingestion (read_events) and aggregation
  4. Profile-based classification logic
  5. Policy diffing and reporting
  6. Top-level command orchestration (run)
  7. Unit tests for several subsystems

This makes behavior changes harder to review and increases accidental drift risk when touching one concern.

2. Current Shape (Verified)

Current file: crates/assay-cli/src/cli/commands/generate.rs (1166 lines).

High-level concern map:

  • Args + validation: GenerateArgs, validate
  • Model DTOs: Policy, Meta, Section, NetSection, Entry
  • Single-run path: read_events, aggregate, generate_from_trace
  • Profile path: generate_from_profile, classify_entry, make_entry_profile
  • Diff path: PolicyDiff helpers, diff_policies, print_policy_diff
  • Entry point: run
  • Tests: classification + diff behavior

3. Constraints (Hard Stop-Lines)

  1. No output contract changes:
  2. No schema drift in generated policy format (yaml/json)
  3. No CLI flag behavior changes
  4. No change in exit code behavior (run still returns Result<i32>, with Ok(0) on success)
  5. Golden assertions must prove policy output, --diff output, and read_events diagnostics remain stable
  6. No semantic drift in classification:
  7. Wilson/laplace/min_runs/new_is_risky logic remains identical
  8. No diff-output semantic drift:
  9. Added/removed/changed calculation remains identical
  10. Output order remains deterministic independent of insertion order
  11. No hidden tolerance changes:
  12. read_events parse/skip/error-rate behavior unchanged

4. Research Baseline (Best Practices, Feb 2026)

Primary guidance used for this plan:

  1. Rust API Guidelines: keep modules focused and APIs explicit (C-CONV, C-STRUCT, C-ITER).
  2. https://rust-lang.github.io/api-guidelines/checklist.html
  3. Clippy docs: prefer specific maintainability lints and tests over abstract complexity scores.
  4. https://rust-lang.github.io/rust-clippy/stable/index.html
  5. Test execution discipline: deterministic, fast feedback loops (nextest and targeted gates).
  6. https://www.nexte.st/

Applied policy for this RFC:

  • Test-first characterization on behavior-sensitive paths
  • Extract-only changes per phase
  • Small, linear PRs with explicit non-goals

5. Target Module Layout

Proposed end-state under crates/assay-cli/src/cli/commands/generate/:

  • mod.rs:
  • public run(args: GenerateArgs) -> Result<i32>
  • module wiring/re-exports
  • args.rs:
  • GenerateArgs
  • GenerateArgs::validate
  • model.rs:
  • Policy, Meta, Section, NetSection, Entry
  • serialize
  • ingest.rs:
  • Stats, Aggregated
  • read_events, aggregate
  • profile.rs:
  • generate_from_trace, generate_from_profile
  • classify_entry, make_entry_profile, make_entry_simple
  • diff.rs:
  • EntryFingerprint, EntryChange, SectionDiff, PolicyDiff
  • parse_existing_policy, diff_policies, print_policy_diff
  • tests:
  • prefer per-module #[cfg(test)] for locality and to avoid widening visibility
  • keep helper visibility minimal (pub(crate) only when required)

Compatibility requirement:

  • Keep command dispatch path unchanged (generate::run remains callable from command router).

6. Execution Plan

G1 - Freeze Tests (Behavior Characterization)

Add targeted characterization tests before moving logic:

  1. read_events contract:
  2. skip empty/comment lines
  3. unparsable lines count/warn behavior
  4. hard error when all lines invalid
  5. warnings snapshot: stable core diagnostics for skipped lines and high-error-rate path
  6. run mode gating:
  7. requires exactly one of --input or --profile
  8. explicit edge cases: both-set, neither-set, --diff with missing output file
  9. assert error class and expected exit behavior at command boundary
  10. classification invariants:
  11. stable allow/review/skip transitions
  12. risk override precedence
  13. min-runs gate behavior
  14. diff invariants:
  15. added/removed/changed semantics unchanged
  16. deterministic stderr output independent of insertion order
  17. output goldens:
  18. generated policy YAML snapshot with normalized dynamic fields
  19. --diff stderr snapshot with stable summary line and (no changes) path

G1 minimal test matrix (must exist before any extraction PR):

  1. generate_contract_policy_yaml_golden
  2. generate_contract_diff_stderr_golden
  3. generate_contract_read_events_warnings_golden
  4. generate_contract_mode_gating_none_or_both
  5. generate_contract_mode_gating_diff_missing_output
  6. generate_contract_diff_deterministic_on_shuffled_input

Gate:

  • cargo test -p assay-cli generate -- --nocapture
  • cargo check -p assay-cli

G2 - Extract DTO/Args Layer (No Logic Moves Yet)

Scope:

  • Move args + model DTOs + serialize to args.rs / model.rs
  • Keep function bodies unchanged
  • Preserve serde/clap attrs exactly (no rename/default/order drift)
  • Preserve default values exactly (including float defaults and bool switches)

Gate:

  • cargo test -p assay-cli generate -- --nocapture
  • cargo clippy -p assay-cli -- -D warnings

G3 - Extract Ingestion/Aggregation

Scope:

  • Move Stats, Aggregated, read_events, aggregate into ingest.rs
  • Preserve all warning/error strings
  • Consolidate diagnostics through local constants/helpers to reduce accidental wording drift

Gate:

  • cargo test -p assay-cli generate -- --nocapture
  • cargo check -p assay-cli

G4 - Extract Profile/Classification Logic

Scope:

  • Move profile generation/classification helpers into profile.rs
  • Keep algorithm and ordering unchanged
  • Guardrail: if profile.rs grows beyond ~400 LOC, split follow-up into classify.rs and profile_emit.rs

Gate:

  • cargo test -p assay-cli generate -- --nocapture
  • cargo clippy -p assay-cli -- -D warnings

G5 - Extract Diff Subsystem

Scope:

  • Move diff structs/helpers into diff.rs
  • Keep summary output format and counts unchanged

Gate:

  • cargo test -p assay-cli generate -- --nocapture
  • cargo check -p assay-cli

G6 - Final Orchestration Cleanup

Scope:

  • Reduce mod.rs to orchestration only
  • Keep run signature and return semantics unchanged
  • Keep dispatch compatibility: crate::cli::commands::generate::run remains unchanged for callers
  • No non-generate command import churn beyond module path rewiring

Gate:

  • cargo test -p assay-cli generate -- --nocapture
  • cargo test -p assay-cli --lib -- --nocapture
  • cargo clippy -p assay-cli -- -D warnings

7. PR Slicing Strategy

Recommended PR sequence:

  1. PR-G1: tests-only freeze
  2. PR-G2: args/model extraction
  3. PR-G3: ingest extraction
  4. PR-G4: profile extraction
  5. PR-G5: diff extraction
  6. PR-G6: final mod.rs cleanup

Each PR must include:

  • In-scope section
  • Non-goals section
  • Contract gates section
  • Output impact statement (none)
  • Acceptance checks section with explicit old->new mapping for moved functions

8. Risks and Mitigations

  1. Risk: subtle classification drift during extraction
  2. Mitigation: G1 characterization tests and unchanged helper signatures
  3. Risk: diff noise or changed reporting semantics
  4. Mitigation: freeze diff tests and keep summary formatting assertions
  5. Risk: accidental CLI behavior drift
  6. Mitigation: mode-gating tests and unchanged run entrypoint
  7. Risk: snapshot brittleness from dynamic fields
  8. Mitigation: normalize timestamp/path fields in golden helpers, assert stable core diagnostics

9. Definition of Done

RFC-003 is done when:

  1. generate.rs orchestration module is reduced and concerns are split into focused modules
  2. Existing behavior is preserved under frozen tests
  3. No output/schema/exit behavior changes are introduced
  4. All G1-G6 gates are green on CI