Files
yoloyolo/.planning/research/STACK.md
T
2026-03-26 16:54:31 +01:00

216 lines
8.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Technology Stack
**Project:** NetSynth v1.1 — Custom Sound Mappings
**Researched:** 2026-03-26
**Scope:** Additions/changes only. Existing stack (gopacket, go-pcap, go-lame, cobra) is validated and unchanged.
---
## Existing Stack (Do Not Re-research)
| Technology | Version | Status |
|------------|---------|--------|
| `github.com/gopacket/gopacket` | v1.5.0 | Validated in v1.0, unchanged |
| `github.com/packetcap/go-pcap` | v0.0.0-20251215 | Validated in v1.0, unchanged |
| `github.com/sjzar/go-lame` | v0.0.9 | Validated in v1.0, unchanged |
| `github.com/spf13/cobra` | v1.10.2 | Validated in v1.0, unchanged |
| Hand-rolled sine oscillator + EMA | — | Validated in v1.0, extend in place |
| Ordered `[]Rule` classifier | — | Validated in v1.0, extend in place |
---
## New Dependencies for v1.1
### TOML Config Parsing
| Technology | Version | Purpose | Why |
|------------|---------|---------|-----|
| `github.com/BurntSushi/toml` | v1.6.0 | Parse `netsynth.toml` config files | Single-function `toml.Decode()` into a struct. The `MetaData.Undecoded()` method catches unknown keys in user configs — surfacing typos like `frequncy` rather than silently ignoring them. This is the right behavior for a config file tool. v1.6.0 released December 2025, Go 1.18+ required. Zero indirect dependencies. |
**Version confirmed:** v1.6.0, December 18, 2025, via pkg.go.dev and GitHub releases page.
**Why not `pelletier/go-toml v2`:** go-toml v2.3.0 (March 2026) is faster but the performance difference is irrelevant — config is read once at startup. go-toml v2's `Strict` mode can detect unknown keys but requires more setup than BurntSushi's `MetaData.Undecoded()`. BurntSushi's API is simpler for this use case and has clearer error message patterns for user-facing config mistakes.
### Config Auto-Discovery
No new dependency. Use Go stdlib only:
```go
// Probe order: --config flag > ./netsynth.toml > ~/.config/netsynth/config.toml
func findConfigPath(flagValue string) (string, bool) {
if flagValue != "" {
return flagValue, true
}
if _, err := os.Stat("./netsynth.toml"); err == nil {
return "./netsynth.toml", true
}
if dir, err := os.UserConfigDir(); err == nil {
p := filepath.Join(dir, "netsynth", "config.toml")
if _, err := os.Stat(p); err == nil {
return p, true
}
}
return "", false
}
```
`os.UserConfigDir()` returns `$XDG_CONFIG_HOME` if set, else `$HOME/.config` on Linux/macOS — confirmed against Go stdlib docs. No third-party XDG library needed.
### Additional Waveform Types
No new dependency. Extend the existing `synth.Oscillator` in place.
Square, sawtooth, and triangle are pure math — each is ~3 lines. The existing oscillator uses a phase accumulator (0.01.0 range), which is the right representation for all four waveforms:
```go
// Waveform enum addition to synth package
type Waveform int
const (
WaveformSine Waveform = iota
WaveformSquare
WaveformSawtooth
WaveformTriangle
)
// Per-sample generation (replaces math.Sin call in Advance())
func sample(phase float64, w Waveform) float64 {
switch w {
case WaveformSquare:
if phase < 0.5 { return 1.0 }
return -1.0
case WaveformSawtooth:
return 2*phase - 1.0
case WaveformTriangle:
if phase < 0.5 { return 4*phase - 1.0 }
return 3.0 - 4*phase
default: // WaveformSine
return math.Sin(2 * math.Pi * phase)
}
}
```
The `Oscillator` struct gains a `Waveform` field; `Advance()` dispatches to `sample()`. Harmonics still work the same way — each harmonic's phase is `phase * ratio`, which maps correctly for all waveform types.
---
## Installation Delta
```bash
# Add only this new dependency
go get github.com/BurntSushi/toml@v1.6.0
```
No changes to build flags. `CGO_ENABLED=1` still required for go-lame.
---
## Integration Points
### Where Config Feeds Existing Code
The TOML config needs to override two existing data structures:
1. **`synth.ClassFreqConfigs`** (map in `synth/config.go`) — user can override `BaseHz` and add a `Waveform` field per class
2. **`classify.DefaultRules`** (slice in `classify/rules.go`) — user can prepend custom rules before the defaults
The config loader should apply overrides at startup before any other initialization. The cleanest integration is:
```
cmd/netsynth/main.go
-> config.Load(path) // returns *AppConfig
-> classify.MergeRules(cfg) // prepend user rules to DefaultRules
-> synth.ApplyOverrides(cfg) // patch ClassFreqConfigs entries
```
Both `classify.DefaultRules` and `synth.ClassFreqConfigs` are currently package-level vars — they can be replaced or cloned at startup without changing the downstream pipeline.
### TOML Struct Shape
The config schema maps naturally to the existing types:
```toml
# netsynth.toml
[[rules]]
protocol = "tcp"
dst_port = 8443
class = "my-https-alt"
[sounds.my-https-alt]
frequency = 195.0
waveform = "square"
[sounds.ICMP]
frequency = 80.0 # override built-in
waveform = "triangle"
```
```go
type AppConfig struct {
Rules []RuleConfig `toml:"rules"`
Sounds map[string]SoundConfig `toml:"sounds"`
}
type RuleConfig struct {
Protocol string `toml:"protocol"`
DstPort uint16 `toml:"dst_port"`
Class string `toml:"class"`
}
type SoundConfig struct {
Frequency float64 `toml:"frequency"`
Waveform string `toml:"waveform"` // "sine"|"square"|"sawtooth"|"triangle"
}
```
Use `toml.Decode()` and check `meta.Undecoded()` to warn on unknown keys.
---
## What NOT to Add
| Avoid | Why | What to Do Instead |
|-------|-----|-------------------|
| `adrg/xdg` or any XDG library | `os.UserConfigDir()` in stdlib already handles `$XDG_CONFIG_HOME` on Linux — confirmed | Use `os.UserConfigDir()` directly |
| `pelletier/go-toml v2` | No advantage over BurntSushi for a single-file startup read; `MetaData.Undecoded()` in BurntSushi is more ergonomic for typo detection | `github.com/BurntSushi/toml` |
| `spf13/viper` | Massive dependency (brings in 20+ transitive deps) for a use case that is one TOML file — Viper adds remote config, env var binding, hot reload, none of which are needed | `BurntSushi/toml` + manual flag override |
| Any waveform/audio library | Square/sawtooth/triangle are 3 lines of math each; no library adds value | Extend `synth.Oscillator` in place |
| `gopkg.in/yaml.v3` or JSON config | TOML is explicitly specified for this milestone and is the right format for user-editable config files (comments supported, less noisy than JSON) | TOML only |
---
## Version Compatibility
| Package | Version | Compatible With | Notes |
|---------|---------|-----------------|-------|
| `BurntSushi/toml` | v1.6.0 | Go 1.18+ | No issues with Go 1.24 |
| `os.UserConfigDir()` | stdlib | Go 1.13+ | Returns `$XDG_CONFIG_HOME` or `$HOME/.config` on Linux |
---
## Confidence Assessment
| Area | Confidence | Source |
|------|------------|--------|
| BurntSushi/toml v1.6.0 version | HIGH | pkg.go.dev confirmed, GitHub releases confirmed |
| `os.UserConfigDir()` XDG behavior | HIGH | Official Go stdlib docs at pkg.go.dev/os |
| Waveform math (no library needed) | HIGH | Trivial math, Dylan Meeus Go audio blog confirms the same approach |
| go-toml v2.3.0 version | HIGH | pkg.go.dev confirmed |
| Recommendation of BurntSushi over go-toml v2 | MEDIUM | Based on API ergonomics for the specific `Undecoded()` use case; both would work |
---
## Sources
- `pkg.go.dev/github.com/BurntSushi/toml` — v1.6.0 confirmed, December 18, 2025
- `github.com/BurntSushi/toml/releases` — v1.6.0 release notes, TOML 1.1 enabled by default
- `pkg.go.dev/github.com/pelletier/go-toml/v2` — v2.3.0 confirmed, March 24, 2026
- `pkg.go.dev/os#UserConfigDir` — XDG_CONFIG_HOME behavior on Linux confirmed via official Go docs
- `dylanmeeus.github.io/posts/audio-from-scratch-pt8/` — Go waveform synthesis from scratch, confirms no library needed
- `github.com/golang/go/issues/76320` — UserConfigDir XDG_CONFIG_HOME discussion (Nov 2025), confirms existing stdlib support on Linux
---
*Stack research for: NetSynth v1.1 — Custom Sound Mappings milestone*
*Researched: 2026-03-26*