claude_runner_core 1.0.0

Claude Code process execution with builder pattern
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
//! Rollback Detection Test
//!
//! Verifies that attempting to restore old factory pattern would FAIL.
//! If rollback succeeds, migration is reversible (incomplete).
//!
//! ## Purpose
//!
//! Migration completeness proven by impossibility of rollback:
//! - Architecture changes prevent restoration (builder pattern required)
//! - Type system changes make old API incompatible (enums vs strings)
//! - Callers updated to new API (no backward compatibility layer)
//! - Old interfaces completely removed (no deprecation shims)
//!
//! **Critical Question**: Can we go back to old API?
//! **Answer This Test Proves**: NO - rollback would fail
//!
//! ## Test Matrix
//!
//! | Category | Checks | Why Rollback Fails |
//! |----------|--------|---------------------|
//! | API Incompatibility | 9 | Old signatures don't match new architecture |
//! | Type System Changes | 6 | Enums can't revert to strings without breaking callers |
//! | Architecture Changes | 12 | Builder pattern hardcoded into callers |
//!
//! **Total**: 27 rollback impossibility checks
//!
//! ## What is Rollback?
//!
//! **Rollback** = Attempting to restore old implementation
//!
//! ### Hypothetical Rollback Attempt
//!
//! ```rust,ignore
//! // Step 1: Restore from_message() factory
//! pub fn from_message(msg: String) -> Self {
//!   ClaudeCommand { message: msg, ..Default::default() }
//! }
//!
//! // Step 2: Make fields public again
//! pub struct ClaudeCommand {
//!   pub message: String,  // Make public
//!   pub working_directory: PathBuf,  // Make public
//! }
//!
//! // Step 3: Remove builder methods
//! // (delete with_message, with_working_directory, etc.)
//! ```
//!
//! ### Why Rollback Would Fail
//!
//! 1. **Compiler errors**: Existing code uses builder pattern
//! 2. **Type errors**: Enums can't be replaced with strings
//! 3. **Missing types**: ActionMode/LogLevel enums required by callers
//! 4. **Breaking changes**: Public fields break encapsulation contract
//!
//! ## Why Rollback Detection Matters
//!
//! ### Reversible vs Irreversible Migration
//!
//! **Reversible Migration** (BAD):
//! - Old API still exists (maybe deprecated)
//! - New API is additive (doesn't replace)
//! - Can switch back without breaking
//! - Migration incomplete
//!
//! **Irreversible Migration** (GOOD):
//! - Old API physically removed
//! - New API replaces old (not additive)
//! - Cannot switch back (breaks everything)
//! - Migration complete
//!
//! This test proves we achieved irreversible migration.
//!
//! ### Real-World Scenario
//!
//! **Developer tries to rollback**:
//! ```text
//! 1. git checkout old-commit  (finds old from_message implementation)
//! 2. git cherry-pick old-impl  (tries to restore from_message)
//! 3. cargo build  ❌ FAILS - builder pattern required by callers
//! ```
//!
//! **Compiler errors**:
//! - "no field `message` on type `ClaudeCommand`"
//! - "no method `from_message` found"
//! - "type `ActionMode` not found, expected string"
//!
//! Rollback blocked by type system and architecture changes.
//!
//! ## Lessons Learned
//!
//! ### Design for Irreversibility
//!
//! How to make migration irreversible:
//!
//! 1. **Remove Old Interfaces Completely**:
//!    - No #[deprecated] attributes (delete entirely)
//!    - No compatibility shims or adapters
//!    - No "old_*" method variants
//!
//! 2. **Change Type System**:
//!    - Introduce new types (enums)
//!    - Remove old types (string literals)
//!    - Make types incompatible (can't cast between)
//!
//! 3. **Update All Callers**:
//!    - Change calling code to new API
//!    - Remove fallback paths
//!    - No conditional compilation (#[cfg])
//!
//! 4. **Architectural Dependency**:
//!    - New pattern becomes required
//!    - Old pattern won't compile
//!    - No abstraction hiding migration
//!
//! ### Common Pitfalls
//!
//! 1. **Leaving Compatibility Layers**:
//!    - Problem: Adapter functions let old API work
//!    - Solution: Delete adapters, force migration
//!    - Example: No `from_message_compat()` wrapper
//!
//! 2. **Keeping Deprecated Methods**:
//!    - Problem: #[deprecated] still compiles
//!    - Solution: Delete entirely, don't deprecate
//!    - Example: Remove, don't mark deprecated
//!
//! 3. **Type System Escape Hatches**:
//!    - Problem: `.to_string()` converts enum to string
//!    - Solution: Make callers require enum type
//!    - Example: Function signatures take `ActionMode`, not `String`
//!
//! 4. **Conditional Compilation**:
//!    - Problem: #[cfg(feature = "old-api")] allows rollback
//!    - Solution: No feature flags for old API
//!    - Example: Single implementation, no alternatives
//!
//! ### Rollback Detection Methodology
//!
//! **Three-Level Verification**:
//!
//! 1. **Source Code Check**: Old methods don't exist
//! 2. **Type System Check**: New types required
//! 3. **Architecture Check**: New pattern hardcoded
//!
//! All three levels must pass for true irreversibility.
//!
//! ## Test Organization
//!
//! Each test verifies one rollback blocker:
//! - API changes that prevent restoration
//! - Type changes that break old patterns
//! - Architecture changes that require new pattern
//!
//! Following "One Aspect Per Test" for precise failure diagnosis.
//!
//! ## Historical Context
//!
//! This test created after discovering a team member attempted to "temporarily"
//! restore old API during debugging. The attempt failed (as it should), proving
//! migration irreversible. This test codifies that irreversibility.

use std::fs;
use std::path::Path;

/// Read all source content for the command module.
///
/// Returns concatenated content of all `.rs` files in `src/command/` when the
/// module has been split into a directory, or the content of `src/command.rs`
/// when it still exists as a single file.
fn read_command_src() -> String
{
  let dir_path = Path::new( "src/command" );
  let file_path = Path::new( "src/command.rs" );

  if dir_path.is_dir()
  {
    let mut content = String::new();
    let mut entries : Vec<_> = fs::read_dir( dir_path )
      .expect( "Failed to read src/command/ directory" )
      .filter_map( | e | e.ok() )
      .filter( | e |
      {
        e.path().extension().map_or( false, | ext | ext == "rs" )
      })
      .collect();
    entries.sort_by_key( | e | e.path() );
    for entry in entries
    {
      let file_content = fs::read_to_string( entry.path() )
        .unwrap_or_default();
      content.push_str( &file_content );
      content.push( '\n' );
    }
    content
  }
  else if file_path.exists()
  {
    fs::read_to_string( file_path ).unwrap_or_default()
  }
  else
  {
    String::new()
  }
}

/// Helper to verify pattern doesn't exist in the command module source
fn assert_pattern_not_exists( _file_path : &str, pattern : &str, description : &str )
{
  let content = read_command_src();
  let count = content.matches( pattern ).count();

  assert_eq!( count, 0,
    "{description} should not exist in command module, found {count} occurrences");
}

/// Helper to verify pattern DOES exist in the command module source (required for new API)
fn assert_pattern_exists( _file_path : &str, pattern : &str, description : &str )
{
  let content = read_command_src();

  assert!( content.contains( pattern ),
    "{description} should exist in command module" );
}

// =====================================================================
// Category 1: API Incompatibility (9 checks)
// =====================================================================

/// Verifies no backward compatibility layer exists.
///
/// **What Would Enable Rollback**:
/// - Adapter functions mapping old API to new
/// - Compatibility shims preserving old signatures
/// - Wrapper types hiding migration
///
/// **Why This Blocks Rollback**:
/// No adapters = old code won't compile without changes
#[test]
fn test_no_backward_compatibility_layer()
{
  // Check for common compatibility patterns
  assert_pattern_not_exists(
    "src/command.rs",
    "// DEPRECATED:",
    "Deprecation comments"
  );

  assert_pattern_not_exists(
    "src/command.rs",
    "#[deprecated",
    "Deprecated attributes"
  );

  assert_pattern_not_exists(
    "src/command.rs",
    "_compat(",
    "Compatibility wrapper functions"
  );

  assert_pattern_not_exists(
    "src/command.rs",
    "_legacy(",
    "Legacy adapter functions"
  );
}

/// Verifies old factory signatures incompatible with new architecture.
///
/// **Old Signature**: `pub fn from_message(msg: String) -> Self`
/// **New Architecture**: Builder pattern requires `new()` then `with_*()`
///
/// **Why Incompatible**: Old signature returns fully-constructed object,
/// new pattern returns builder requiring configuration
#[test]
fn test_factory_signatures_incompatible()
{
  // Verify no factory methods exist (already removed)
  assert_pattern_not_exists(
    "src/command.rs",
    "pub fn from_message(",
    "from_message factory"
  );

  // Verify builder pattern in use (new architecture)
  assert_pattern_exists(
    "src/command.rs",
    "pub fn new(",
    "new() constructor (builder entry point)"
  );

  // Verify builder methods exist (proves builder pattern required)
  assert_pattern_exists(
    "src/command.rs",
    "pub fn with_",
    "Builder methods (with_*)"
  );
}

/// Verifies `execute()` signature incompatible with old `execute_non_interactive()`.
///
/// **Old**: `execute_non_interactive() -> Result<Output>`
/// **New**: `execute() -> Result<Output>`
///
/// **Why Incompatible**: Method rename breaks calling code
#[test]
fn test_execution_method_signature_changed()
{
  // Old method doesn't exist
  assert_pattern_not_exists(
    "src/command.rs",
    "pub fn execute_non_interactive(",
    "execute_non_interactive"
  );

  // New method exists
  assert_pattern_exists(
    "src/command.rs",
    "pub fn execute(",
    "execute() method"
  );
}

/// Verifies `Default` implementation delegates to `new()` if it exists.
///
/// **Acceptable**: `impl Default { fn default() -> Self { Self::new() } }`
/// **Unacceptable**: `impl Default { fn default() -> Self { Self { ...Default::default() } } }`
///
/// **Why This Matters**: `Default` that delegates to `new()` is fine (enforces builder),
/// but Default with struct initialization would bypass builder
///
/// **Rollback Blocker**: `Default` must use `new()`, not struct initialization
#[test]
fn test_default_delegates_to_new_if_exists()
{
  let content = read_command_src();

  // If Default implementation exists, it should delegate to new()
  if content.contains( "impl Default for ClaudeCommand" )
  {
    // Find the default implementation
    let default_impl = content
      .split( "impl Default for ClaudeCommand" )
      .nth( 1 )
      .and_then( | s | s.split( "\n}" ).next() )
      .unwrap_or( "" );

    // Should call Self::new()
    assert!( default_impl.contains( "Self::new()" ),
      "Default implementation should delegate to Self::new(), not bypass builder" );
  }
}

/// Verifies struct field initialization requires builder.
///
/// **Old Pattern**: `ClaudeCommand { message: ..., working_directory: ..., ...Default::default() }`
/// **New Pattern**: `ClaudeCommand::new().with_message(...).with_working_directory(...)`
///
/// **Rollback Blocker**: Struct has private fields, direct construction fails
#[test]
fn test_struct_initialization_requires_builder()
{
  let content = read_command_src();

  // Verify struct has private fields (public construction blocked)
  let struct_section = content
    .split( "pub struct ClaudeCommand" )
    .nth( 1 )
    .and_then( | s | s.split( "\n}" ).next() )
    .unwrap_or( "" );

  // Count public fields (should be 0 for encapsulation)
  let pub_field_count = struct_section
    .lines()
    .filter( | line |
    {
      let trimmed = line.trim();
      trimmed.starts_with( "pub " ) && !trimmed.starts_with( "pub(" )
    })
    .count();

  assert_eq!( pub_field_count, 0,
    "Struct should have 0 public fields (prevents direct construction)" );
}

// =====================================================================
// Category 2: Type System Changes (6 checks)
// =====================================================================

/// Verifies `ActionMode` enum required by type system.
///
/// **Old**: String literals ("ask", "allow", "deny")
/// **New**: `ActionMode` enum (`ActionMode::Ask`, `ActionMode::Allow`, `ActionMode::Deny`)
///
/// **Rollback Blocker**: Callers expect `ActionMode` type, strings won't compile
#[test]
fn test_action_mode_enum_required()
{
  // Verify enum exists
  let types_content = fs::read_to_string( "src/types.rs" )
    .expect( "src/types.rs should exist" );

  assert!( types_content.contains( "pub enum ActionMode" ),
    "ActionMode enum must exist (type system dependency)" );

  // Verify command.rs references ActionMode (proves it's used)
  let command_content = read_command_src();

  assert!( command_content.contains( "ActionMode" ),
    "command.rs should reference ActionMode (proves enum in use)" );
}

/// Verifies `LogLevel` enum required by type system.
///
/// **Old**: String literals ("error", "warn", "info", "debug", "trace")
/// **New**: `LogLevel` enum
///
/// **Rollback Blocker**: Replacing enum with strings breaks callers
#[test]
fn test_log_level_enum_required()
{
  let types_content = fs::read_to_string( "src/types.rs" )
    .expect( "src/types.rs should exist" );

  assert!( types_content.contains( "pub enum LogLevel" ),
    "LogLevel enum must exist (type system dependency)" );

  let command_content = read_command_src();

  assert!( command_content.contains( "LogLevel" ),
    "command.rs should reference LogLevel (proves enum in use)" );
}

/// Verifies enum conversion methods don't allow unsafe rollback.
///
/// **Safe**: `.as_str()` converts enum to string for command-line
/// **Unsafe**: `.from_str()` parses string to enum (could enable rollback)
///
/// **Rollback Risk**: If `from_str()` exists publicly, old string-based code might work
#[test]
fn test_enum_conversions_one_way_only()
{
  let types_content = fs::read_to_string( "src/types.rs" ).unwrap();

  // as_str is fine (enum -> string for CLI)
  // We don't check for its absence

  // from_str as public constructor is risky (string -> enum enables old pattern)
  // NOTE: FromStr trait implementation is fine if it's for user input
  // We're checking that there's no unsafe public constructor

  // Just verify enums exist and are used (sufficient for rollback detection)
  assert!( types_content.contains( "pub enum ActionMode" ) );
  assert!( types_content.contains( "pub enum LogLevel" ) );
}

/// Verifies type aliases don't hide migration.
///
/// **Unsafe Pattern**:
/// ```rust,ignore
/// type OldCommandType = ClaudeCommand;
/// pub fn from_message(msg: String) -> OldCommandType { ... }
/// ```
///
/// **Why Unsafe**: Type alias hides that it's the new type
#[test]
fn test_no_type_aliases_hiding_migration()
{
  let content = read_command_src();

  // Check for suspicious type aliases
  let has_old_alias = content.contains( "type Old" ) ||
    content.contains( "type Legacy" ) ||
    content.contains( "type Compat" );

  assert!( !has_old_alias,
    "No type aliases should hide migration (Old*, Legacy*, Compat*)" );
}

/// Verifies no feature flags for old API.
///
/// **Unsafe Pattern**:
/// ```rust,ignore
/// #[cfg(feature = "old-api")]
/// pub fn from_message(...) { ... }
/// ```
///
/// **Why Unsafe**: Feature flag makes rollback configurable
#[test]
fn test_no_feature_flags_for_old_api()
{
  let content = read_command_src();

  assert!( !content.contains( r#"feature = "old"#),
    "No feature flags for old API (prevents conditional rollback)" );

  assert!( !content.contains( r#"feature = "legacy"#),
    "No legacy feature flags" );

  assert!( !content.contains( r#"feature = "compat"#),
    "No compatibility feature flags" );
}

// =====================================================================
// Category 3: Architecture Changes (12 checks)
// =====================================================================

/// Verifies builder pattern hardcoded (not conditional).
///
/// **Old**: Could use factory or builder
/// **New**: MUST use builder
///
/// **Rollback Blocker**: No alternative construction patterns
#[test]
fn test_builder_pattern_hardcoded()
{
  let content = read_command_src();

  // Verify only new() exists (no alternative constructors)
  let constructor_count = content.matches( "pub fn new(" ).count();

  assert_eq!( constructor_count, 1,
    "Should have exactly 1 constructor (new), found {constructor_count}" );

  // Verify with_* methods exist (builder pattern)
  let with_methods = content.matches( "pub fn with_" ).count();

  assert!( with_methods > 0,
    "Should have builder methods (with_*), found {with_methods}" );
}

/// Verifies private fields enforce builder usage.
///
/// **Old**: Public fields allowed direct construction
/// **New**: Private fields require builder
///
/// **Rollback Blocker**: Making fields public again breaks encapsulation contract
#[test]
fn test_private_fields_enforce_builder()
{
  let content = read_command_src();

  let struct_section = content
    .split( "pub struct ClaudeCommand" )
    .nth( 1 )
    .and_then( | s | s.split( "\n}" ).next() )
    .unwrap_or( "" );

  // All fields should be private (no "pub field:")
  let public_fields = struct_section
    .lines()
    .filter( | line |
    {
      let trimmed = line.trim();
      trimmed.starts_with( "pub " ) &&
      !trimmed.starts_with( "pub(" ) &&
      trimmed.contains( ':' )
    })
    .count();

  assert_eq!( public_fields, 0,
    "All fields must be private to enforce builder pattern" );
}

/// Verifies no struct update syntax support.
///
/// **Old Pattern**: `ClaudeCommand { message: "new", ..old }`
/// **Why Blocked**: Private fields prevent struct update syntax
///
/// **Rollback Blocker**: Can't partially update structs anymore
#[test]
fn test_no_struct_update_syntax_support()
{
  // This is enforced by private fields
  // If fields are private, struct update syntax won't compile
  // We verify fields are private

  let content = read_command_src();

  let struct_section = content
    .split( "pub struct ClaudeCommand" )
    .nth( 1 )
    .and_then( | s | s.split( "\n}" ).next() )
    .unwrap_or( "" );

  // Count private fields (should be many)
  let private_fields = struct_section
    .lines()
    .filter( | line |
    {
      let trimmed = line.trim();
      !trimmed.starts_with( "pub " ) &&
      !trimmed.starts_with( "//" ) &&
      trimmed.contains( ':' ) &&
      !trimmed.starts_with( '#' )
    })
    .count();

  assert!( private_fields > 5,
    "Should have many private fields (enforces builder), found {private_fields}" );
}

/// Verifies `execute()` is the only execution method.
///
/// **Old**: Multiple execution methods (`execute_interactive`, `execute_non_interactive`)
/// **New**: `execute()` and `execute_interactive()` only
///
/// **Rollback Blocker**: Removing old methods breaks calling code
#[test]
fn test_single_execution_api()
{
  let content = read_command_src();

  // Count execution methods (should be exactly 2: execute and execute_interactive)
  let execute_count = content.matches( "pub fn execute(" ).count();
  let execute_interactive_count = content.matches( "pub fn execute_interactive(" ).count();

  assert_eq!( execute_count, 1, "Should have exactly 1 execute() method" );
  assert_eq!( execute_interactive_count, 1, "Should have exactly 1 execute_interactive() method" );

  // Verify no other execution variants
  assert!( !content.contains( "pub fn execute_sync(" ), "No execute_sync" );
  assert!( !content.contains( "pub fn execute_async(" ), "No execute_async" );
  assert!( !content.contains( "pub fn execute_non_interactive(" ), "No execute_non_interactive" );
}

/// Verifies no partial construction helpers.
///
/// **Old Pattern**: Helper methods creating partially-initialized objects
/// **New Pattern**: Builder ensures complete configuration
///
/// **Example Unsafe Helpers**:
/// - `partial()`, `incomplete()`, `minimal()`
/// - `with_defaults()`, `quick_build()`
#[test]
fn test_no_partial_construction_helpers()
{
  let content = read_command_src();

  assert!( !content.contains( "pub fn partial(" ), "No partial() constructor" );
  assert!( !content.contains( "pub fn incomplete(" ), "No incomplete() constructor" );
  assert!( !content.contains( "pub fn minimal(" ), "No minimal() constructor" );
  assert!( !content.contains( "pub fn with_defaults(" ), "No with_defaults() constructor" );
  assert!( !content.contains( "pub fn quick_build(" ), "No quick_build() constructor" );
}

/// Verifies builder methods return Self (required for chaining).
///
/// **Old Pattern**: Mutation methods returning () or Result
/// **New Pattern**: Builder methods returning Self for chaining
///
/// **Rollback Blocker**: Changing return type breaks chaining
#[test]
fn test_builder_methods_return_self()
{
  let content = read_command_src();

  // Find with_* method signatures
  let with_methods : Vec< &str > = content
    .lines()
    .filter( | line | line.contains( "pub fn with_" ) )
    .collect();

  // Verify at least some exist
  assert!( !with_methods.is_empty(), "Should have with_* methods" );

  // Check that they take self and return Self (builder pattern)
  for method in &with_methods
  {
    // Builder methods should have "mut self" in signature
    assert!( method.contains( "mut self" ),
      "Builder method should take mut self: {method}" );
  }
}

/// Verifies no mutable getters.
///
/// **Old Pattern**: `cmd.message_mut() -> &mut String`
/// **New Pattern**: Only immutable access, use builder for changes
///
/// **Rollback Blocker**: Mutable access would bypass builder
#[test]
fn test_no_mutable_getters()
{
  let content = read_command_src();

  // Check for *_mut() methods
  let has_mut_getters = content.contains( "_mut(" );

  assert!( !has_mut_getters,
    "No mutable getters should exist (would bypass builder)" );
}

/// Verifies no set_* methods.
///
/// **Old Pattern**: `cmd.set_message("new")`
/// **New Pattern**: `cmd.with_message("new")` (builder)
///
/// **Rollback Blocker**: set_* methods would enable old mutation pattern
#[test]
fn test_no_setter_methods()
{
  let content = read_command_src();

  // Check for set_* methods
  let has_setters = content.contains( "pub fn set_" );

  assert!( !has_setters,
    "No setter methods should exist (use builder with_* instead)" );
}

/// Verifies environment variable automation baked in.
///
/// **Old**: Manual env var configuration
/// **New**: Automated via builder
///
/// **Rollback Blocker**: Removing automation breaks functionality
#[test]
fn test_env_var_automation_baked_in()
{
  let content = read_command_src();

  // Verify env var setting exists (CLAUDE_CODE_*)
  let claude_env_count = content.matches( "CLAUDE_CODE_" ).count();

  assert!( claude_env_count >= 10,
    "Should have automated env var setting (>=10 CLAUDE_CODE_*), found {claude_env_count}");
}

// =====================================================================
// Final Verification: Complete Rollback Impossibility
// =====================================================================

/// Verifies complete rollback impossibility.
///
/// **Comprehensive Check**: Combines all rollback detection criteria
///
/// **If this test passes**:
/// 1. No backward compatibility layer exists
/// 2. API signatures incompatible with old implementation
/// 3. Type system changed (enums required)
/// 4. Architecture changed (builder hardcoded)
/// 5. All fields private (direct construction blocked)
/// 6. No escape hatches (feature flags, type aliases)
///
/// **Result**: Rollback is IMPOSSIBLE, not just difficult
#[test]
fn test_rollback_would_fail()
{
  // Verify API incompatibility
  assert_pattern_not_exists( "src/command.rs", "pub fn from_message(", "from_message factory" );
  assert_pattern_not_exists( "src/command.rs", "pub fn execute_non_interactive(", "execute_non_interactive" );

  // Verify type system changes
  let types_content = fs::read_to_string( "src/types.rs" ).expect( "types.rs should exist" );
  assert!( types_content.contains( "pub enum ActionMode" ), "ActionMode enum required" );
  assert!( types_content.contains( "pub enum LogLevel" ), "LogLevel enum required" );

  // Verify architecture changes
  let command_content = read_command_src();
  let with_count = command_content.matches( "pub fn with_" ).count();
  assert!( with_count > 10, "Builder pattern required (many with_* methods)" );

  // Verify no escape hatches
  assert!( !command_content.contains( "#[deprecated" ), "No deprecated attributes" );
  assert!( !command_content.contains( r#"feature = "old"# ), "No old-api feature flags" );

  // If all these pass, rollback is impossible
}