Backlog/lib/zargs/todo/implementation_plan_v2.md

487 lines
12 KiB
Markdown

# Implementation Plan v2 - Refined
## Critical Changes from v1
1. **Add string handling strategy early (Phase 1.3)**
2. **Define error types upfront (Phase 1.4)**
3. **Emphasize test-driven development throughout**
4. **Clarify memory ownership at every step**
5. **Add missing helpers (kebab-case conversion, etc.)**
---
## Phase 1: Foundation (Week 1: Days 1-3)
### 1.1 ArgumentType Enum
**File:** `src/ArgumentType.zig`
**Duration:** 1 day
- [ ] Define `ArgumentType` enum
- [ ] Implement `fromZigType(comptime T: type) ArgumentType`
- [ ] Implement `matches(self, other) bool`
- [ ] **TESTS:** Type detection for all supported types
**Key Decision:** Support `?T` by unwrapping to underlying type
---
### 1.2 ParsedValue Union
**File:** `src/ArgumentType.zig`
**Duration:** 1 day
- [ ] Define `ParsedValue` tagged union
- [ ] Implement `fromString(type, string, allocator) !ParsedValue`
- [ ] Implement `toTypedValue(comptime T: type, parsed) T`
- [ ] **TESTS:** Conversions for all types, error cases
**Key Decision:** Allocate strings into caller-provided arena
---
### 1.3 String Handling Strategy
**File:** `src/utils.zig`
**Duration:** 0.5 days
- [ ] Implement `toKebabCase(comptime name: []const u8) []const u8`
- Convert camelCase/snake_case to kebab-case
- Comptime function, returns comptime string
- [ ] Document string ownership model:
- Arena owns all parsed strings
- Comptime strings (field names, literals) not duplicated
- Runtime strings (argv) duplicated into arena
- [ ] **TESTS:** kebab-case conversion edge cases
**Key Decision:** Use arena allocator for all dynamic strings
---
### 1.4 Error Type Definitions
**File:** `src/errors.zig`
**Duration:** 0.5 days
- [ ] Define comprehensive error set:
```zig
pub const Error = error{
IncompatibleArgumentType,
UnknownArgument,
InvalidValue,
InvalidIntegerValue,
InvalidBooleanValue,
InvalidEnumValue,
MissingArgumentValue,
OutOfMemory,
};
```
- [ ] Document when each error occurs
- [ ] Consider error payloads for context
**Key Decision:** Separate error type allows clear API contracts
---
## Phase 2: Metadata Extraction (Week 1: Days 4-5)
### 2.1 Metadata Structures
**File:** `src/metadata.zig`
**Duration:** 0.5 days
- [ ] Define `ArgumentMetadata` struct
- [ ] Define `ModuleInfo` struct
- [ ] Define `FieldMeta` (what goes in `pub const meta = .{...}`)
- [ ] Document structure ownership
---
### 2.2 Comptime Metadata Extraction
**File:** `src/metadata.zig`
**Duration:** 1.5 days
- [ ] `extractFieldMetadata(comptime T: type, comptime field: Field) FieldMeta`
- Get `T.meta.field_name` if exists
- Generate defaults for missing fields
- Convert field name to kebab-case
- Extract default value
- [ ] `extractDocComment(comptime T: type, comptime field_name: []const u8) []const u8`
- Return empty for now (future: parse doc comments)
- [ ] `formatDefaultValue(comptime T: type, value: T, allocator) ![]const u8`
- Format bool, int, string, enum, list
- [ ] **TESTS:** Metadata extraction with various struct configurations
**Key Decision:** All metadata extraction is comptime
---
## Phase 3: Core Registry (Week 2: Days 6-9)
### 3.1 Registry Structure
**File:** `src/ArgumentRegistry.zig`
**Duration:** 1 day
- [ ] Define struct with all fields
- [ ] Implement `init(allocator) ArgumentRegistry`
- [ ] Implement `deinit()`
- [ ] **TESTS:** Init/deinit, memory leak detection
**Key Decision:** Use StringHashMap for O(1) lookups
---
### 3.2 argv Caching
**File:** `src/ArgumentRegistry.zig`
**Duration:** 0.5 days
- [ ] Cache argv on first access
- [ ] Implement `isHelpRequested() bool`
- [ ] **TESTS:** Help detection, caching behavior
**Key Decision:** Registry owns argv memory
---
### 3.3 Metadata Registration with Collision Detection
**File:** `src/ArgumentRegistry.zig`
**Duration:** 2 days
- [ ] `registerMetadata(comptime T: type, opts: ParseOptions) !void`
- Create/get module entry
- For each field:
- Extract metadata
- Check for existing argument
- If exists and types match: warn, add module
- If exists and types differ: error with locations
- If new: store metadata
- [ ] Implement collision detection logic
- [ ] Format error messages with source locations
- [ ] **TESTS:** Compatible collisions, incompatible collisions, error messages
**Key Decision:** Source locations captured via `@src()`, stored as-is (compile-time strings)
---
### 3.4 Struct Tracking
**File:** `src/ArgumentRegistry.zig`
**Duration:** 0.5 days
- [ ] Track parsed structs by type name
- [ ] Skip re-registration if already parsed
- [ ] **TESTS:** Multiple parse calls with same struct
---
## Phase 4: Argument Parsing (Week 2-3: Days 10-14)
### 4.1 Argv Parsing Infrastructure
**File:** `src/parsing.zig`
**Duration:** 1.5 days
- [ ] `parseArgv() !void`
- Iterate cached argv
- Dispatch to appropriate parser
- [ ] `parseArg(arg: []const u8) !void`
- Handle `--long=value`
- Handle `--long value`
- Handle `--flag` (bool)
- [ ] `parseShortArg(short: u8) !void`
- Look up by short name
- Handle value/flag
- [ ] **TESTS:** All argument formats, unknown arguments
**Key Decision:** Duplicate parsed strings into arena
---
### 4.2 Value Parsing with List Support
**File:** `src/parsing.zig`
**Duration:** 1.5 days
- [ ] Parse integers with range checking
- [ ] Parse booleans (true/false, 1/0, yes/no)
- [ ] Parse strings (already strings, but duplicate)
- [ ] Parse lists:
- Split on comma
- Also support repeated args: `--list=a --list=b`
- Accumulate into single list
- [ ] Parse enums (stringToEnum)
- [ ] **TESTS:** All types, edge cases, error conditions
**Key Decision:** Support both comma-separated and repeated arguments for lists
---
### 4.3 Struct Reconstruction with Type Safety
**File:** `src/ArgumentRegistry.zig`
**Duration:** 1 day
- [ ] `reconstructStruct(comptime T: type) T`
- For each field:
- Get parsed value by long name
- Convert to field type with comptime assertions
- Fall back to default if not provided
- Handle `?T` (optional) types
- [ ] Runtime type checking for safety
- [ ] **TESTS:** Struct reconstruction, optional fields, defaults
**Key Decision:** Comptime type checks prevent runtime type errors
---
### 4.4 Main parse() Integration
**File:** `src/ArgumentRegistry.zig`
**Duration:** 1 day
- [ ] `parse(comptime T: type, opts: ParseOptions) !T`
- Check parsed_structs
- If new: registerMetadata, parseArgv
- reconstructStruct and return
- Mark as parsed
- [ ] **TESTS:** Full end-to-end parsing, multiple structs
**Key Decision:** Single function handles everything
---
## Phase 5: Help Generation (Week 3: Days 15-16)
### 5.1 Help Text Generation
**File:** `src/help.zig`
**Duration:** 1 day
- [ ] `getUsageAlloc(allocator) ![]const u8`
- Write header
- Write global options (--help)
- For each module:
- Write module name
- For each argument:
- Format `-s, --long <VALUE> Help text [default: X]`
- Calculate alignment for readability
- [ ] **TESTS:** Help text format, alignment, grouping
**Key Decision:** Generate fresh each time (acceptable performance)
---
## Phase 6: Public API (Week 3-4: Day 17)
### 6.1 Module Exports and Documentation
**File:** `src/main.zig`
**Duration:** 1 day
- [ ] Export all public types
- [ ] Add top-level module documentation
- [ ] Define version constant
- [ ] Document global registry pattern
- [ ] **TESTS:** Ensure exports are accessible
---
## Phase 7: Comprehensive Testing (Week 4: Days 18-21)
### 7.1 Unit Test Coverage
**Duration:** 2 days
- [ ] Achieve 100% coverage of:
- Type detection and conversion
- Metadata extraction
- Collision detection
- Parsing logic
- Struct reconstruction
- Help generation
- [ ] Test error paths
- [ ] Test edge cases
---
### 7.2 Integration Tests
**Duration:** 1 day
- [ ] Multi-module scenarios
- [ ] Parse order independence
- [ ] Help text workflow
- [ ] Persistence workflow
---
### 7.3 Memory and Safety Tests
**Duration:** 1 day
- [ ] Memory leak detection on all tests
- [ ] Test cleanup on error paths
- [ ] Arena allocator correctness
- [ ] Stress tests (many arguments, large values)
---
## Phase 8: Examples and Documentation (Week 5: Days 22-24)
### 8.1 Examples
**Duration:** 2 days
- [ ] `examples/simple.zig` - Basic usage
- [ ] `examples/game_engine.zig` - Multi-module
- [ ] `examples/persistence.zig` - Help text persistence
- [ ] Ensure all examples compile and run
---
### 8.2 Documentation
**Duration:** 1 day
- [ ] Write comprehensive README
- [ ] Document all public APIs
- [ ] Add usage examples to doc comments
- [ ] Document design decisions and tradeoffs
---
## Phase 9: Build and Integration (Week 5: Day 25)
### 9.1 Build System
**Duration:** 0.5 days
- [ ] Configure build.zig
- [ ] Test, example, and install steps
- [ ] Verify Zig 0.14 compatibility
---
### 9.2 Engine Integration
**Duration:** 0.5 days
- [ ] Import into Backlog engine
- [ ] Test with actual engine modules
- [ ] Document engine-specific usage
---
## Phase 10: Polish (Week 5: Day 25)
### 10.1 Final Review
**Duration:** 0.5 days
- [ ] Review all error messages
- [ ] Run formatter
- [ ] Check for TODOs
- [ ] Verify no memory leaks
- [ ] Performance check
---
## Daily Checklist Template
For each day of implementation:
- [ ] Write tests FIRST for new functionality
- [ ] Implement feature
- [ ] Ensure tests pass
- [ ] Check for memory leaks
- [ ] Update documentation
- [ ] Commit with clear message
---
## Test-Driven Development Workflow
1. **Write failing test** - Define expected behavior
2. **Implement minimum** - Make test pass
3. **Refactor** - Improve code quality
4. **Repeat** - Next feature
---
## Memory Ownership Rules
### Simple Rules:
1. **Registry owns:** argv, all parsed strings (via arena)
2. **Caller owns:** allocator passed to registry
3. **Comptime owns:** field names, type names, meta strings
4. **Return values:** Structs contain pointers into registry arena
- Valid until registry.deinit()
- Document this lifetime requirement
### Rule of Thumb:
- If it comes from argv → duplicate into arena
- If it's comptime → use as-is
- If it's dynamically formatted → allocate from arena
---
## Success Metrics
- [ ] All tests pass (100% coverage target)
- [ ] Zero memory leaks detected
- [ ] All examples compile and run
- [ ] Documentation complete and clear
- [ ] Integration with Backlog engine successful
- [ ] Collision detection works correctly
- [ ] Help generation produces readable output
- [ ] Can demonstrate persistence workflow
---
## Open Questions Resolved
1. **Positional arguments?** No, deferred to v2
2. **Config files?** No, separate feature
3. **Environment variables?** No, separate feature
4. **Shell completion?** No, v2 feature
5. **Validators?** No, v2 feature
All features deferred to maintain focus on core use case.
---
## Confidence Level: 95%
**Why higher:**
- Addressed string handling explicitly
- Clarified memory ownership model
- Emphasized TDD approach
- Defined error types upfront
- Covered missing utility functions
**Remaining concerns:**
- Comptime complexity (will discover during Phase 2)
- Edge cases in parsing (will catch with comprehensive tests)
**Mitigation:**
- Build incrementally
- Test each component in isolation
- Integration test early (Phase 7)
---
## Go/No-Go Decision Points
### After Phase 1 (Day 3):
**Check:** Type system working correctly?
- If yes: proceed
- If no: revisit type design
### After Phase 2 (Day 5):
**Check:** Metadata extraction compiling and working?
- If yes: proceed
- If no: simplify metadata approach
### After Phase 4 (Day 14):
**Check:** Full parse cycle working end-to-end?
- If yes: proceed to polish
- If no: debug integration issues
### After Phase 7 (Day 21):
**Check:** All tests passing, no leaks?
- If yes: ready for production
- If no: fix issues before release
---
## Implementation Notes
- Keep each file under 500 lines
- Prefer clarity over cleverness
- Document all comptime behavior
- Write tests for every public function
- Use meaningful error messages
- Follow Zig style guide
**Ready to implement!** 🚀