# Phase 4: Power User Features - Context **Gathered:** 2026-03-26 **Status:** Ready for planning ## Phase Boundary Two additive CLI features: BPF capture filter (`--filter` flag) and offline pcap file input (`--read` flag). Both feed into the existing classify → aggregate → synthesis pipeline. No changes to audio synthesis, classification rules, or MP3 encoding. ## Implementation Decisions ### Pcap file timing - **D-01:** Use packet timestamps from the pcap file to assign packets to 500ms time windows. Processing is fast — a 10-minute pcap produces a 10-minute MP3 in seconds. - **D-02:** Preserve time gaps as silence. Windows with zero packets during gaps produce silent audio sections. MP3 duration faithfully matches the pcap file's time span. ### Flag interaction rules - **D-03:** `--read` and `-i` are mutually exclusive. Error if both provided. `--read` replaces `-i` as the packet source. - **D-04:** `--filter` works with both `-i` (live capture) and `--read` (pcap file). BPF filter applies to whichever packet source is active. - **D-05:** `--read` without `-o` derives output filename from input: `capture.pcap` → `capture.mp3`. ### Offline processing feedback - **D-06:** Bookend messages: `"Reading ..."` at start, then protocol summary + `"Saved"` line at end. No progress bar — processing is fast enough that it would flash by. - **D-07:** `--verbose` works with `--read` — per-window protocol activity lines scroll by quickly. Consistent behavior regardless of packet source. ### Claude's Discretion - BPF filter validation approach (pre-validate before opening capture vs let go-pcap/gopacket reject it) - Pcap file format detection and error messages for corrupt/unreadable files - Implementation of timestamp-based windowing (new aggregation path vs adapter that feeds existing Aggregate()) - How to handle pcap files with no packets (reuse existing zero-packet guard from OUT-03) ## Canonical References **Downstream agents MUST read these before planning or implementing.** ### Project context - `.planning/PROJECT.md` — Core value, constraints (Go, MP3 output, non-interactive) - `.planning/REQUIREMENTS.md` — CAPT-05 (BPF filter), CAPT-06 (pcap file input) ### Prior phase context - `.planning/phases/01-capture-and-classification/01-CONTEXT.md` — Phase 1 decisions; pure-Go pcap backend, classifier design, privilege model - `.planning/phases/02-audio-synthesis-engine/02-CONTEXT.md` — Phase 2 decisions; tone mapping, mixing, encoding - `.planning/phases/03-pipeline-integration-and-mvp/03-CONTEXT.md` — Phase 3 decisions; hash-bucketing, encoding feedback format ### Key source files (integration points) - `cmd/netsynth/main.go` — CLI wiring; Cobra flags, pipeline assembly, encoding feedback output - `capture/capture.go` — `OpenCapture()` and `StartCapture()` — will need filter parameter and pcap file reading path - `aggregate/window.go` — `Aggregate()` function using real-time ticks; pcap mode needs timestamp-based windowing - `encode/mp3.go` — `RunSynthesis()` entry point; no changes expected - `classify/types.go` — `WindowSnapshot` struct (input contract for synthesis) ### Stack decisions - `CLAUDE.md` — Technology stack section; `packetcap/go-pcap` for capture, `gopacket/gopacket` for decoding - `.planning/research/STACK.md` — Library recommendations and alternatives ## Existing Code Insights ### Reusable Assets - `capture.StartCapture(ctx, iface)` — live capture pipeline; pcap file reading needs a parallel entry point returning the same `<-chan gopacket.Packet` - `classify.NewClassifier(rules)` / `classifier.Classify(pkt)` — reused unchanged for both live and pcap sources - `aggregate.Aggregate(done, classified, windowMs, onSnapshot)` — reused for live; pcap needs timestamp-based variant - `encode.RunSynthesis([]WindowSnapshot, path)` — reused unchanged - `aggregate.PrintSummary()` / `aggregate.PrintWindowLine()` — reused for both modes ### Established Patterns - Channel-based pipeline: capture → classify → aggregate → synthesis - `done <-chan struct{}` for shutdown signaling via `signal.NotifyContext` - Buffered channels for stage decoupling (512 capture, 1024 classified, 8 aggregate) - `io.Writer` injection for testable output - Cobra flag-based CLI with `RunE` function ### Integration Points - `main.go` — Add `--filter` and `--read` Cobra flags; branch `run()` into live vs pcap paths - `capture/capture.go` — Add filter parameter to `OpenCapture()`; add new `ReadPcapFile()` function - `aggregate/window.go` — Add timestamp-based windowing function for offline mode (or adapter) ## Specific Ideas - `--read` + `--filter` is a key workflow: capture broad with tcpdump, then sonify a subset - Output filename derivation (`capture.pcap` → `capture.mp3`) follows ffmpeg conventions - Pcap file processing should feel instant — no unnecessary waiting or progress indicators - BPF filter errors should fail fast before any capture begins, with a clear message ## Deferred Ideas None — discussion stayed within phase scope --- *Phase: 04-power-user-features* *Context gathered: 2026-03-26*