--- phase: 11 plan: 02 subsystem: config tags: [print-config, group-headers, toml-groups, user-facing-output] dependency_graph: requires: [synth/config.go FreqConfig.Group field from Phase 11 Plan 01, classify/types.go AllClasses() with 35 entries] provides: [Group-ordered PrintConfig output, [groups] TOML support, applyGroupOverrides function] affects: [config/config.go, config/config_test.go] tech_stack: added: [] patterns: [rawConfig Groups field for TOML [groups] table, groupOrder canonical slice for section ordering] key_files: created: [] modified: - config/config.go - config/config_test.go decisions: - "Non-canonical group names (user-invented via [groups]) emitted after canonical groups in alphabetical order" - "builtinByGroup built from result.FreqCfgs[cls].Group (effective group after reassignment) not from synth defaults" metrics: duration: ~5min completed: "2026-03-27" tasks: 2 files_modified: 2 --- # Phase 11 Plan 02: Group-Ordered PrintConfig and [groups] TOML Support Summary **One-liner:** Refactored PrintConfig to emit group section headers (Infrastructure, Web, Mail, Remote Access, File Transfer, Database, Discovery, VoIP, Unknown) with classes sorted by ascending BaseHz, and added [groups] TOML table support for user-defined protocol-to-group reassignment. ## What Was Built ### Task 1: Add [groups] TOML support and refactor PrintConfig for group headers **config/config.go** — Three changes: **1. Groups field on rawConfig:** ```go type rawConfig struct { Sounds map[string]SoundOverride `toml:"sounds"` Rules []RawRule `toml:"rules"` Groups map[string]string `toml:"groups"` } ``` **2. applyGroupOverrides function** — overlays [groups] reassignments onto FreqConfig.Group in-place. Unknown class names emit a stderr warning and are skipped (not an error). Unknown group names are silently accepted (users can invent custom groups). Called in Load() after merge(). **3. PrintConfig refactored** — replaced flat AllClasses() iteration with: - `groupOrder` canonical slice: `["Infrastructure", "Web", "Mail", "Remote Access", "File Transfer", "Database", "Discovery", "VoIP", "Unknown"]` - Built-in classes grouped by their effective Group field, sorted ascending by BaseHz within each group - Section headers emitted as `# GroupName\n\n` - Non-canonical group names (user-invented) emitted after canonical groups in alphabetical order - User-defined classes (not in AllClasses()) emitted under `# User-defined` section ### Task 2: Add tests for group headers, group reassignment, and unknown class warning **config/config_test.go** — 4 new test functions: | Test | What It Covers | |------|---------------| | `TestPrintConfigGroupHeaders` | GRP-02: all 8 populated group headers present in canonical order | | `TestLoadGroupOverride` | GRP-03: [groups] reassigns IMAP from Mail to Web, Hz/waveform unchanged | | `TestLoadGroupUnknownClass` | D-09: unknown class in [groups] produces no error, map size unchanged | | `TestPrintConfigGroupReassignment` | GRP-03: PrintConfig places reassigned IMAP between Web and Mail headers | ## Verification Results ``` go test ./... ok github.com/netsynth/netsynth/aggregate (cached) ok github.com/netsynth/netsynth/capture (cached) ok github.com/netsynth/netsynth/classify ok github.com/netsynth/netsynth/cmd/netsynth ok github.com/netsynth/netsynth/config ok github.com/netsynth/netsynth/encode ok github.com/netsynth/netsynth/synth ``` All 7 packages pass. ## Commits | Task | Commit | Description | |------|--------|-------------| | 1 | 374282e | feat(11-02): add [groups] TOML support and group-ordered PrintConfig | | 2 | 7bf3ea1 | test(11-02): add group header and reassignment tests (GRP-02, GRP-03) | ## Deviations from Plan None - plan executed exactly as written. ## Known Stubs None — PrintConfig group output is fully wired to FreqConfig.Group field populated in Phase 11 Plan 01. No placeholder data. ## Self-Check: PASSED