10 KiB
phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
| phase | plan | type | wave | depends_on | files_modified | autonomous | requirements | must_haves | |||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 03-pipeline-integration-and-mvp | 02 | execute | 2 |
|
|
false |
|
|
Purpose: Implements CAPT-03 — the final integration that makes netsynth -i eth0 -o out.mp3 produce a real audio file from live network traffic.
Output: Updated main.go with RunSynthesis call, encoding status/saved messages, and correct summary ordering.
<execution_context> @$HOME/.claude/get-shit-done/workflows/execute-plan.md @$HOME/.claude/get-shit-done/templates/summary.md </execution_context>
@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/03-pipeline-integration-and-mvp/03-CONTEXT.md @.planning/phases/03-pipeline-integration-and-mvp/03-01-SUMMARY.mdFrom encode/mp3.go:
// RunSynthesis consumes a slice of WindowSnapshots, renders audio via OscillatorBank,
// and encodes to MP3 at outputPath.
// Returns an error if zero packets were captured (OUT-03).
func RunSynthesis(snapshots []classify.WindowSnapshot, outputPath string) error
From aggregate/accumulator.go:
const DefaultWindowMs = 500
From aggregate/summary.go:
func PrintSummary(w io.Writer, totals map[classify.TrafficClass]int64)
func AccumulateTotals(totals map[classify.TrafficClass]int64, snap classify.WindowSnapshot)
From cmd/netsynth/main.go (CURRENT — lines 91-109 are the integration zone):
// Accumulate snapshots for synthesis (Phase 3 will pass to encode.RunSynthesis)
totals := make(map[classify.TrafficClass]int64)
var collectedSnapshots []classify.WindowSnapshot
for snap := range snapshots {
collectedSnapshots = append(collectedSnapshots, snap)
aggregate.AccumulateTotals(totals, snap)
}
// TODO(phase-3): Pass collectedSnapshots to encode.RunSynthesis(collectedSnapshots, outputPath)
_ = collectedSnapshots
// Print exit summary (CLAS-03)
dropped := atomic.LoadInt64(droppedPtr)
if dropped > 0 {
fmt.Fprintf(os.Stderr, "\nWarning: %d packets dropped (channel buffer full)\n", dropped)
}
aggregate.PrintSummary(os.Stderr, totals)
return nil
Step 1: Add import
Add "github.com/netsynth/netsynth/encode" to the import block. The time import already exists.
Step 2: Replace lines 99-109 with the following sequence
Remove:
// TODO(phase-3): Pass collectedSnapshots to encode.RunSynthesis(collectedSnapshots, outputPath)
_ = collectedSnapshots
// Print exit summary (CLAS-03)
dropped := atomic.LoadInt64(droppedPtr)
if dropped > 0 {
fmt.Fprintf(os.Stderr, "\nWarning: %d packets dropped (channel buffer full)\n", dropped)
}
aggregate.PrintSummary(os.Stderr, totals)
return nil
Replace with:
// D-08: Print protocol summary BEFORE encoding — user sees stats immediately
dropped := atomic.LoadInt64(droppedPtr)
if dropped > 0 {
fmt.Fprintf(os.Stderr, "\nWarning: %d packets dropped (channel buffer full)\n", dropped)
}
aggregate.PrintSummary(os.Stderr, totals)
// D-07: Encoding status line
fmt.Fprintf(os.Stderr, "Encoding %d windows to %s...\n", len(collectedSnapshots), outputPath)
encodeStart := time.Now()
if err := encode.RunSynthesis(collectedSnapshots, outputPath); err != nil {
return fmt.Errorf("synthesis failed: %w", err)
}
encodeElapsed := time.Since(encodeStart)
// D-09: Saved confirmation with path, audio duration, file size, encoding time
audioDuration := float64(len(collectedSnapshots)) * float64(aggregate.DefaultWindowMs) / 1000.0
info, statErr := os.Stat(outputPath)
if statErr != nil {
return fmt.Errorf("stat output file: %w", statErr)
}
fmt.Fprintf(os.Stderr, "Saved %s (%.1fs, %d KB, encoded in %.1fs)\n",
outputPath, audioDuration, info.Size()/1024, encodeElapsed.Seconds())
return nil
Step 3: Update the Long description
Change line 32 from:
Long: "NetSynth captures network traffic, classifies it by protocol, and (in future phases) synthesizes an ambient MP3 soundscape.",
to:
Long: "NetSynth captures network traffic, classifies it by protocol, and synthesizes an ambient MP3 soundscape.",
Key details:
encode.RunSynthesisalready handles the zero-packet guard (returns error, no corrupt file created) — we just propagate the error viafmt.Errorf("synthesis failed: %w", err)- Audio duration is computed from snapshot count, NOT wall-clock time:
float64(len(collectedSnapshots)) * float64(aggregate.DefaultWindowMs) / 1000.0— uses float64 to avoid integer truncation for short captures (Pitfall 4) os.Statis only called AFTER confirmingRunSynthesisreturned nil (Pitfall 5)- The
_ = collectedSnapshotsline and the TODO comment are completely removed cd /home/dev/workspace/yoloyolo && go build -o /tmp/netsynth-test ./cmd/netsynth && echo "BUILD OK" && go test ./... -count=1 2>&1 | tail -20 <acceptance_criteria>- cmd/netsynth/main.go contains
"github.com/netsynth/netsynth/encode"in imports - cmd/netsynth/main.go contains
encode.RunSynthesis(collectedSnapshots, outputPath) - cmd/netsynth/main.go contains
fmt.Fprintf(os.Stderr, "Encoding %d windows to %s...\n" - cmd/netsynth/main.go contains
fmt.Fprintf(os.Stderr, "Saved %s (%.1fs, %d KB, encoded in %.1fs)\n" - cmd/netsynth/main.go does NOT contain
TODO(phase-3) - cmd/netsynth/main.go does NOT contain
_ = collectedSnapshots - cmd/netsynth/main.go
PrintSummarycall appears BEFOREencode.RunSynthesiscall (D-08) - cmd/netsynth/main.go audioDuration uses
float64(len(collectedSnapshots)) * float64(aggregate.DefaultWindowMs) / 1000.0(not integer division) go build ./cmd/netsynthexits 0go test ./... -count=1all packages pass </acceptance_criteria> The complete v1 MVP pipeline is wired: capture -> classify -> aggregate -> synthesize -> encode MP3. Protocol summary prints before encoding. Encoding status and saved confirmation messages display path, audio duration, file size, and encoding time. Binary builds successfully. All tests pass.
- cmd/netsynth/main.go contains
Binary builds
go build -o /tmp/netsynth-verify ./cmd/netsynth
No TODO(phase-3) remaining
grep -rn 'TODO(phase-3)' cmd/ classify/ synth/ encode/ aggregate/
No bare ClassUnknown references (from Plan 01, verify still clean)
grep -rn 'ClassUnknown[^1234]' classify/ synth/ encode/ cmd/ aggregate/ | grep -v test | grep -v '//'
</verification>
<success_criteria>
- Binary builds and runs: `netsynth -i lo -o out.mp3` produces a valid MP3
- Protocol summary appears before encoding messages on stderr
- Saved line shows path, audio duration, file size, encoding time
- Zero-packet capture returns error without creating a file
- All tests pass (`go test ./... -count=1`)
- No TODO(phase-3) stubs remain
</success_criteria>
<output>
After completion, create `.planning/phases/03-pipeline-integration-and-mvp/03-02-SUMMARY.md`
</output>