12 KiB
Implementation Plan v2 - Refined
Critical Changes from v1
- Add string handling strategy early (Phase 1.3)
- Define error types upfront (Phase 1.4)
- Emphasize test-driven development throughout
- Clarify memory ownership at every step
- 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
ArgumentTypeenum - 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
ParsedValuetagged 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:
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
ArgumentMetadatastruct - Define
ModuleInfostruct - Define
FieldMeta(what goes inpub 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_nameif exists - Generate defaults for missing fields
- Convert field name to kebab-case
- Extract default value
- Get
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)
- Handle
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
- For each field:
- 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]
- Format
- 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 usageexamples/game_engine.zig- Multi-moduleexamples/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
- Write failing test - Define expected behavior
- Implement minimum - Make test pass
- Refactor - Improve code quality
- Repeat - Next feature
Memory Ownership Rules
Simple Rules:
- Registry owns: argv, all parsed strings (via arena)
- Caller owns: allocator passed to registry
- Comptime owns: field names, type names, meta strings
- 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
- Positional arguments? No, deferred to v2
- Config files? No, separate feature
- Environment variables? No, separate feature
- Shell completion? No, v2 feature
- 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! 🚀