# Retrospective ## Milestone: v1.0 — MVP **Shipped:** 2026-03-26 **Phases:** 4 | **Plans:** 11 | **Timeline:** 3 days (2026-03-24 -> 2026-03-26) **LOC:** 3,254 Go | **Files:** 84 modified ### What Was Built - Config-driven packet classifier with 12 protocol rules and 4 hash-bucketed unknown classes - Live packet capture via pure Go go-pcap with privilege detection and non-blocking channel pipeline - Additive synthesis engine: per-class oscillators, EMA amplitude smoothing, constant-power stereo mixing - MP3 encoding via embedded LAME, zero-packet guard - End-to-end pipeline with clean Ctrl+C shutdown - BPF filter and offline pcap file sonification with timestamp-based windowing ### What Worked - Risk-ordered phases: hardest foundation first (capture), then synthesis in isolation, then integration — no phase blocked on another's bugs - TDD approach in executor agents caught signature mismatches early - Pure Go capture layer (go-pcap) avoided libpcap dependency headaches - Hand-rolled synthesis kept dependencies minimal and code understandable - Wave-based parallel execution for independent plans ### What Was Inefficient - Some SUMMARY.md files had empty one-liner fields, causing noisy milestone extraction - Phase 4 research could have been lighter — BPF/pcap APIs were straightforward ### Patterns Established - Ordered []Rule slice for classifier (first-match-wins, extensible) - io.Writer injection for testable stderr output - Buffered channels between pipeline stages (512-1024) to absorb bursts - Package-level globals for Cobra flag binding - Timestamp-based windowing for non-live sources ### Key Lessons - Embedding C source (go-lame) is a good tradeoff: CGo at build time only, no runtime dependency - go-audio/wav was unnecessary — writing PCM bytes directly to LameWriter is simpler - Hash-bucketed unknowns (4 classes) are sufficient for audio distinction without k-means complexity ## Milestone: v1.1 — Custom Sound Mappings **Shipped:** 2026-03-26 **Phases:** 3 | **Plans:** 6 | **Timeline:** 1 day (2026-03-26) **LOC:** ~4,675 Go (+1,421 from v1.0) | **Packages:** 7 ### What Was Built - Four waveform types (sine, square, sawtooth, triangle) with bandlimited additive synthesis - TOML config system: auto-discovery, partial overrides, unknown-key validation, `--config` flag - User-defined `[[rules]]` classification rules with first-match-wins prepend semantics - Auto-frequency assignment (FNV-32a hash) for custom class names - `--print-config` flag with commented TOML output and source annotations - LoadResult struct pattern for clean config-to-pipeline data flow ### What Worked - Incremental config extension: Phase 6 built the config package, Phase 7 extended it cleanly - TDD plans (type: tdd in frontmatter) produced higher-quality code with fewer regressions - FNV-32a frequency assignment was verified experimentally during research before planning - Worktree isolation for parallel executor agents prevented merge conflicts - Reusing existing patterns (Rule struct, NewClassifier injection, Cobra flag-on-root) kept code consistent ### What Was Inefficient - SUMMARY.md one-liner extraction continued to be noisy — summary-extract needs improvement - Phase 5 could potentially have been merged with Phase 6 (waveform + config together) ### Patterns Established - LoadResult struct for multi-value config returns (extensible without breaking callers) - Pointer fields (`*float64`, `*string`) for partial TOML override semantics - FNV-32a hash for deterministic resource assignment from string keys - Flag-on-root pattern for early-exit operations (--list-interfaces, --print-config) - `addAutoFreqEntries()` pattern: fill gaps in config before merge ### Key Lessons - BurntSushi/toml Undecoded() works with array-of-tables (verified experimentally) - Manual string building beats TOML encoder when you need inline comments/annotations - Config extension is smooth when the original Load() was designed with clean boundaries ## Cross-Milestone Trends | Metric | v1.0 | v1.1 | |--------|------|------| | Phases | 4 | 3 | | Plans | 11 | 6 | | Days | 3 | 1 | | LOC | 3,254 | 4,675 | | Avg plan duration | ~8 min | ~5 min |