Files
yoloyolo/.planning/phases/06-config-package-and-sound-overrides/06-02-PLAN.md
T
2026-03-26 20:51:07 +01:00

263 lines
10 KiB
Markdown

---
phase: 06-config-package-and-sound-overrides
plan: 02
type: execute
wave: 2
depends_on: ["06-01"]
files_modified:
- encode/mp3.go
- encode/mp3_test.go
- cmd/netsynth/main.go
autonomous: true
requirements:
- CFG-03
must_haves:
truths:
- "User passes --config /path/to/file.toml and the tool uses that file for sound overrides"
- "User passes --config /nonexistent.toml and the tool exits with a clear error before capture"
- "User runs without --config and auto-discovery kicks in (or defaults used silently)"
- "RunSynthesis uses the merged config map instead of hardcoded ClassFreqConfigs"
artifacts:
- path: "cmd/netsynth/main.go"
provides: "--config flag, config.Load call, passing merged map to RunSynthesis"
contains: "configPath"
- path: "encode/mp3.go"
provides: "RunSynthesis with freqCfgs parameter"
contains: "freqCfgs map[classify.TrafficClass]synth.FreqConfig"
- path: "encode/mp3_test.go"
provides: "Updated tests for new RunSynthesis signature"
key_links:
- from: "cmd/netsynth/main.go"
to: "config/config.go"
via: "config.Load(configPath)"
pattern: "config\\.Load"
- from: "cmd/netsynth/main.go"
to: "encode/mp3.go"
via: "encode.RunSynthesis(snapshots, outputPath, freqCfgs)"
pattern: "encode\\.RunSynthesis.*freqCfgs"
- from: "encode/mp3.go"
to: "synth/bank.go"
via: "synth.NewBank(1.0, freqCfgs) using passed-in config"
pattern: "synth\\.NewBank.*freqCfgs"
---
<objective>
Wire the config package into the CLI and synthesis pipeline. Add `--config` flag to Cobra, call `config.Load` at startup, change `RunSynthesis` signature to accept the merged config map, and update all call sites.
Purpose: Completes CFG-03 (explicit --config flag) and D-10 (RunSynthesis signature change). After this plan, the end-to-end flow works: user creates TOML -> tool loads it -> synthesis uses overridden frequencies/waveforms.
Output: Updated `cmd/netsynth/main.go`, `encode/mp3.go`, `encode/mp3_test.go`
</objective>
<execution_context>
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
@$HOME/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/06-config-package-and-sound-overrides/06-CONTEXT.md
@.planning/phases/06-config-package-and-sound-overrides/06-01-SUMMARY.md
<interfaces>
<!-- Key types and contracts the executor needs. -->
From config/config.go (created in Plan 01):
```go
// Load finds, parses, validates, and merges a config file.
// configPath is the --config flag value; empty string triggers auto-discovery.
func Load(configPath string) (map[classify.TrafficClass]synth.FreqConfig, error)
```
From encode/mp3.go (current signature to change):
```go
// Current:
func RunSynthesis(snapshots []classify.WindowSnapshot, outputPath string) error
// New:
func RunSynthesis(snapshots []classify.WindowSnapshot, outputPath string, freqCfgs map[classify.TrafficClass]synth.FreqConfig) error
```
From cmd/netsynth/main.go (existing flags pattern):
```go
var (
ifaceName string
listIfaces bool
verbose bool
outputPath string
bpfFilter string
readPath string
)
// Flag registration pattern:
rootCmd.Flags().StringVar(&bpfFilter, "filter", "", "BPF filter expression")
```
From synth/config.go:
```go
var ClassFreqConfigs = map[classify.TrafficClass]FreqConfig{ /* 14 entries */ }
```
</interfaces>
</context>
<tasks>
<task type="auto">
<name>Task 1: Change RunSynthesis signature and update encode tests</name>
<files>encode/mp3.go, encode/mp3_test.go</files>
<read_first>
encode/mp3.go (current RunSynthesis signature and body)
encode/mp3_test.go (current test calls to RunSynthesis)
synth/config.go (ClassFreqConfigs, FreqConfig type)
classify/types.go (TrafficClass type)
</read_first>
<action>
**encode/mp3.go changes:**
1. Add `freqCfgs map[classify.TrafficClass]synth.FreqConfig` as third parameter to RunSynthesis:
```
func RunSynthesis(snapshots []classify.WindowSnapshot, outputPath string, freqCfgs map[classify.TrafficClass]synth.FreqConfig) error
```
2. Change line 57 from:
```
bank := synth.NewBank(1.0, synth.ClassFreqConfigs)
```
to:
```
bank := synth.NewBank(1.0, freqCfgs)
```
3. No other changes to encode/mp3.go.
**encode/mp3_test.go changes:**
4. Update `TestMP3Valid` (line 56): change `RunSynthesis(snaps, tmpPath)` to `RunSynthesis(snaps, tmpPath, synth.ClassFreqConfigs)`.
5. Update `TestZeroPacketError` (line 101): change `RunSynthesis([]classify.WindowSnapshot{}, tmpPath)` to `RunSynthesis([]classify.WindowSnapshot{}, tmpPath, synth.ClassFreqConfigs)`.
6. Update `TestZeroPacketError` (line 121): change `RunSynthesis(zeroSnaps, tmpPath2)` to `RunSynthesis(zeroSnaps, tmpPath2, synth.ClassFreqConfigs)`.
The `synth` import is already present in mp3_test.go.
</action>
<verify>
<automated>cd /home/dev/workspace/yoloyolo && go build ./encode/... && go test ./encode/... -count=1 -run TestZeroPacketError</automated>
</verify>
<acceptance_criteria>
- encode/mp3.go contains `func RunSynthesis(snapshots []classify.WindowSnapshot, outputPath string, freqCfgs map[classify.TrafficClass]synth.FreqConfig) error`
- encode/mp3.go contains `synth.NewBank(1.0, freqCfgs)` (not synth.ClassFreqConfigs)
- encode/mp3_test.go contains `RunSynthesis(snaps, tmpPath, synth.ClassFreqConfigs)`
- encode/mp3_test.go contains `RunSynthesis([]classify.WindowSnapshot{}, tmpPath, synth.ClassFreqConfigs)`
- encode/mp3_test.go contains `RunSynthesis(zeroSnaps, tmpPath2, synth.ClassFreqConfigs)`
- `go build ./encode/...` exits 0
- `go test ./encode/... -count=1 -run TestZeroPacketError` exits 0
</acceptance_criteria>
<done>
RunSynthesis accepts injected config map. All encode tests updated and passing.
</done>
</task>
<task type="auto">
<name>Task 2: Add --config flag and wire config.Load into main.go</name>
<files>cmd/netsynth/main.go</files>
<read_first>
cmd/netsynth/main.go (full file — flag definitions, run function, runLiveMode, runPcapMode)
config/config.go (Load function signature)
encode/mp3.go (updated RunSynthesis signature from Task 1)
</read_first>
<action>
**cmd/netsynth/main.go changes:**
1. Add `configPath` to the var block (after `readPath`):
```go
configPath string // NEW: --config flag (CFG-03)
```
2. Add import for config package in the import block:
```go
"github.com/netsynth/netsynth/config"
```
Also add import for `synth` package (needed for ClassFreqConfigs fallback reference — though config.Load handles this internally):
No — `synth` is NOT needed in main.go. `config.Load` returns the full map. Only add `config` import.
3. Add flag registration in main() after the `readPath` flag line (line 44):
```go
rootCmd.Flags().StringVar(&configPath, "config", "", "Path to TOML config file (default: auto-discover)")
```
4. In the `run` function, add config loading AFTER the BPF filter validation block (after line 80) and BEFORE output path resolution (before line 83). This is per D-11 (fail fast on config errors before capture):
```go
// Load config (CFG-01 through CFG-05, D-11: fail fast)
freqCfgs, err := config.Load(configPath)
if err != nil {
return err
}
```
5. The `freqCfgs` variable must be accessible in both `runLiveMode` and `runPcapMode`. Two approaches:
- Option A: Pass freqCfgs to both functions (cleanest).
- Option B: Store in a package-level var (simpler change).
Use Option A. Change signatures:
- `runLiveMode(cmd *cobra.Command) error` -> `runLiveMode(cmd *cobra.Command, freqCfgs map[classify.TrafficClass]synth.FreqConfig) error`
- `runPcapMode(cmd *cobra.Command) error` -> `runPcapMode(cmd *cobra.Command, freqCfgs map[classify.TrafficClass]synth.FreqConfig) error`
This requires adding `synth` import after all:
```go
"github.com/netsynth/netsynth/synth"
```
Update call sites in `run()`:
- Line 92: `return runPcapMode(cmd)` -> `return runPcapMode(cmd, freqCfgs)`
- Line 94: `return runLiveMode(cmd)` -> `return runLiveMode(cmd, freqCfgs)`
6. In `runLiveMode`, change the RunSynthesis call (line 147):
From: `encode.RunSynthesis(collectedSnapshots, outputPath)`
To: `encode.RunSynthesis(collectedSnapshots, outputPath, freqCfgs)`
7. In `runPcapMode`, change the RunSynthesis call (line 215):
From: `encode.RunSynthesis(collectedSnapshots, outputPath)`
To: `encode.RunSynthesis(collectedSnapshots, outputPath, freqCfgs)`
After all changes, run `go build ./cmd/netsynth/...` to verify compilation.
</action>
<verify>
<automated>cd /home/dev/workspace/yoloyolo && go build ./cmd/netsynth/... && go vet ./cmd/netsynth/... && go test ./... -count=1 2>&1 | tail -20</automated>
</verify>
<acceptance_criteria>
- cmd/netsynth/main.go contains `configPath string`
- cmd/netsynth/main.go contains `rootCmd.Flags().StringVar(&configPath, "config", ""`
- cmd/netsynth/main.go contains `config.Load(configPath)`
- cmd/netsynth/main.go contains `"github.com/netsynth/netsynth/config"` in imports
- cmd/netsynth/main.go contains `encode.RunSynthesis(collectedSnapshots, outputPath, freqCfgs)` (two occurrences — one in runLiveMode, one in runPcapMode)
- cmd/netsynth/main.go contains `runLiveMode(cmd, freqCfgs)` and `runPcapMode(cmd, freqCfgs)`
- `go build ./cmd/netsynth/...` exits 0
- `go vet ./cmd/netsynth/...` exits 0
- `go test ./... -count=1` exits 0 (full suite green)
</acceptance_criteria>
<done>
--config flag registered in Cobra. config.Load called at startup before capture. Merged config map flows through to RunSynthesis in both live and pcap modes. Full test suite passes.
</done>
</task>
</tasks>
<verification>
- `go build ./...` compiles entire project
- `go test ./... -count=1` all tests pass
- `go vet ./...` no issues
- `./netsynth --help` shows `--config` flag in output
</verification>
<success_criteria>
- --config flag appears in CLI help output (CFG-03)
- Explicit --config with missing file produces error before capture (CFG-03)
- RunSynthesis uses injected config map, not hardcoded ClassFreqConfigs (D-10)
- Full test suite passes including encode and config package tests
</success_criteria>
<output>
After completion, create `.planning/phases/06-config-package-and-sound-overrides/06-02-SUMMARY.md`
</output>