--- phase: 07-custom-rules-and-print-config plan: "01" subsystem: config tags: [config, rules, tdd, classification, auto-freq] dependency_graph: requires: [] provides: [LoadResult, RawRule, validateRules, convertRules, autoAssignFreq, addAutoFreqEntries] affects: [cmd/netsynth/main.go] tech_stack: added: ["hash/fnv"] patterns: [LoadResult-struct, FNV-32a-deterministic-hash, TDD-red-green] key_files: created: [] modified: - config/config.go - config/config_test.go - cmd/netsynth/main.go decisions: - "addAutoFreqEntries runs before merge so [sounds.X] overrides apply to user-defined classes" - "merge() warning for unknown class names still fires for [sounds.X] where X is neither built-in nor in [[rules]] -- acceptable harmless warning" - "main.go call site updated to use LoadResult.FreqCfgs -- minimal fix to keep compile; full wiring deferred to Plan 02" metrics: duration: 3min completed: "2026-03-26T20:45:08Z" tasks_completed: 1 files_modified: 3 --- # Phase 7 Plan 01: Config Rule Parsing and LoadResult Summary Extend config package to parse `[[rules]]` TOML blocks, validate them, auto-assign frequencies for new class names using FNV-32a, and return a `LoadResult` struct from `Load()`. ## What Was Built `config.Load()` now returns `LoadResult{FreqCfgs, UserRules, ConfigPath}` instead of a bare map. The new struct is the data contract for Plan 02's CLI wiring and `--print-config` output. **New types and functions in config/config.go:** - `RawRule` struct: `Port *uint16`, `Protocol string`, `Class string` — pointer Port to distinguish missing vs zero - `LoadResult` struct: `FreqCfgs`, `UserRules []classify.Rule`, `ConfigPath string` - `validateRules()`: checks protocol required, class required, valid protocols (tcp/udp/icmp) - `convertRules()`: converts `[]RawRule` to `[]classify.Rule` - `autoAssignFreq()`: FNV-32a hash → deterministic Hz in [1200, 2350] range (24 steps of 50Hz) - `addAutoFreqEntries()`: creates `FreqConfig` entries for new class names, skips built-ins - Import: `hash/fnv` **Key operation order:** `addAutoFreqEntries` runs before `merge` so that `[sounds.MyApp]` sound overrides apply to user-defined classes that were added by auto-freq. ## Tasks Completed | Task | Name | Commit | Files | |------|------|--------|-------| | 1 | RawRule, LoadResult, validation, conversion, auto-freq with TDD | 4b365cd | config/config.go, config/config_test.go, cmd/netsynth/main.go | ## Deviations from Plan ### Auto-fixed Issues **1. [Rule 1 - Bug] Operation order: addAutoFreqEntries must run before merge** - **Found during:** Task 1 GREEN phase - **Issue:** Plan's action section said "merge first, then addAutoFreqEntries" but this caused [sounds.MyApp] overrides to be ignored for user-defined classes (merge only applies to classes already in the map) - **Fix:** Reversed the order — addAutoFreqEntries first (creates the entry), then merge (applies sound overrides) - **Files modified:** config/config.go - **Commit:** 4b365cd **2. [Rule 3 - Blocking] main.go call site updated to use LoadResult** - **Found during:** Task 1 GREEN phase - **Issue:** Plan notes this break is expected but tests wouldn't compile without it - **Fix:** Minimal one-line update: `loadResult, err := config.Load(...)` + `freqCfgs := loadResult.FreqCfgs` - **Files modified:** cmd/netsynth/main.go - **Commit:** 4b365cd ## Test Coverage 21 tests total (8 existing + 13 new): - `TestLoadCustomRules` - TOML [[rules]] block with port/protocol/class - `TestLoadCustomRuleNoPort` - optional port field, DstPort=0 when absent - `TestLoadCustomRuleMissingProtocol` - validation error "protocol is required" - `TestLoadCustomRuleMissingClass` - validation error "class is required" - `TestLoadCustomRuleInvalidProtocol` - validation error "invalid protocol" - `TestLoadCustomRuleUnknownField` - undecoded TOML field error - `TestUserRulesPrepend` - UserRules field usable for prepend pattern - `TestAutoFreqAssignment` - BaseHz in [1200, 2350], WaveformSine - `TestAutoFreqDeterministic` - same class name produces same Hz - `TestAutoFreqSkipsBuiltins` - HTTPS stays at 175.0 default - `TestLoadResultConfigPath` - ConfigPath populated correctly - `TestLoadNoConfigReturnsLoadResult` - returns LoadResult with empty UserRules - All 8 existing tests updated to use `result.FreqCfgs` ## Known Stubs None. All new functions are fully implemented and tested. ## Self-Check: PASSED