fix(02): revise plans based on checker feedback

This commit is contained in:
2026-03-26 11:44:32 +01:00
parent 08f1a87a54
commit 6cbf0366da
4 changed files with 115 additions and 7 deletions
@@ -127,7 +127,7 @@ type WindowSnapshot struct {
6. Verify CGo build works by running `CGO_ENABLED=1 go build ./...` — should succeed with no errors. 6. Verify CGo build works by running `CGO_ENABLED=1 go build ./...` — should succeed with no errors.
NOTE: Do NOT add go-audio/wav. Per research recommendation, skip the WAV intermediate and write PCM bytes directly to LameWriter. This eliminates a dependency and avoids the io.WriteSeeker complication. NOTE: Skipping go-audio/wav — per CONTEXT.md Claude's Discretion grant for "WAV intermediate format usage," the WAV intermediate is unnecessary. Phase 2 research (Pitfall 4) confirmed go-audio/wav requires io.WriteSeeker which bytes.Buffer does not satisfy. Writing interleaved int16 PCM bytes directly to go-lame's LameWriter.Write() is simpler and eliminates one dependency. CLAUDE.md updated to reflect this decision.
</action> </action>
<verify> <verify>
<automated>go version && gcc --version && ffprobe -version && grep "go-lame" go.mod && CGO_ENABLED=1 go build ./...</automated> <automated>go version && gcc --version && ffprobe -version && grep "go-lame" go.mod && CGO_ENABLED=1 go build ./...</automated>
@@ -25,7 +25,7 @@ must_haves:
provides: "Integration test with ffprobe validation and zero-packet guard test" provides: "Integration test with ffprobe validation and zero-packet guard test"
contains: "TestMP3Valid" contains: "TestMP3Valid"
- path: "cmd/netsynth/main.go" - path: "cmd/netsynth/main.go"
provides: "-o flag wiring with timestamp default" provides: "-o flag wiring with timestamp default, snapshot slice accumulator stub"
contains: "outputPath" contains: "outputPath"
key_links: key_links:
- from: "encode/mp3.go" - from: "encode/mp3.go"
@@ -225,7 +225,7 @@ Write tests FIRST, using `os.CreateTemp` for output files and `exec.Command("ffp
</task> </task>
<task type="auto"> <task type="auto">
<name>Task 2: Wire -o output flag into CLI</name> <name>Task 2: Wire -o output flag and snapshot accumulator stub into CLI</name>
<files>cmd/netsynth/main.go</files> <files>cmd/netsynth/main.go</files>
<read_first> <read_first>
- cmd/netsynth/main.go (current Cobra flag setup, run function) - cmd/netsynth/main.go (current Cobra flag setup, run function)
@@ -255,9 +255,16 @@ Add the `-o` / `--output` flag to main.go. Per D-15: defaults to `netsynth-<time
4. Add `"time"` to the imports. 4. Add `"time"` to the imports.
5. Add a comment in the snapshot consumption loop marking where Phase 3 will wire synthesis: 5. Add a snapshot slice accumulator alongside the existing snapshot consumption loop, and a TODO for Phase 3 wiring. Replace the current `for snap := range snapshots` block to also collect snapshots into a slice:
```go ```go
// TODO(phase-3): Pass snapshots to encode.RunSynthesis(snapshots, outputPath) // Accumulate snapshots for synthesis (Phase 3 will pass to encode.RunSynthesis)
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)
``` ```
Do NOT import the encode package yet — Phase 3 handles that. The flag must be functional (parseable, shows in --help) even though the synthesis pipeline isn't wired. Do NOT import the encode package yet — Phase 3 handles that. The flag must be functional (parseable, shows in --help) even though the synthesis pipeline isn't wired.
@@ -271,10 +278,12 @@ Do NOT import the encode package yet — Phase 3 handles that. The flag must be
- cmd/netsynth/main.go contains `netsynth-%s.mp3` - cmd/netsynth/main.go contains `netsynth-%s.mp3`
- cmd/netsynth/main.go contains `time.Now().Format("20060102-150405")` - cmd/netsynth/main.go contains `time.Now().Format("20060102-150405")`
- cmd/netsynth/main.go imports `"time"` - cmd/netsynth/main.go imports `"time"`
- cmd/netsynth/main.go contains `var collectedSnapshots []classify.WindowSnapshot`
- cmd/netsynth/main.go contains `TODO(phase-3)` referencing `encode.RunSynthesis`
- `go build ./cmd/netsynth/` exits 0 - `go build ./cmd/netsynth/` exits 0
- `go run ./cmd/netsynth/ --help` output contains `-o, --output` - `go run ./cmd/netsynth/ --help` output contains `-o, --output`
</acceptance_criteria> </acceptance_criteria>
<done>The -o/--output flag is registered in Cobra, defaults to netsynth-<timestamp>.mp3, visible in --help. Build succeeds. Phase 3 will wire it to RunSynthesis.</done> <done>The -o/--output flag is registered in Cobra, defaults to netsynth-<timestamp>.mp3, visible in --help. Snapshot slice accumulator stub is in place for Phase 3 wiring. Build succeeds.</done>
</task> </task>
</tasks> </tasks>
@@ -284,12 +293,14 @@ Do NOT import the encode package yet — Phase 3 handles that. The flag must be
- `ffprobe` validates the test-generated MP3 (within encode test) - `ffprobe` validates the test-generated MP3 (within encode test)
- `go run ./cmd/netsynth/ --help` shows `-o, --output` flag - `go run ./cmd/netsynth/ --help` shows `-o, --output` flag
- `grep "no packets captured" encode/mp3.go` confirms zero-packet error message - `grep "no packets captured" encode/mp3.go` confirms zero-packet error message
- `grep "collectedSnapshots" cmd/netsynth/main.go` confirms snapshot accumulator stub
</verification> </verification>
<success_criteria> <success_criteria>
- encode/mp3.go produces valid MP3 files from synthetic WindowSnapshots (validated by ffprobe) - encode/mp3.go produces valid MP3 files from synthetic WindowSnapshots (validated by ffprobe)
- Zero-packet guard prevents file creation and returns descriptive error (OUT-03) - Zero-packet guard prevents file creation and returns descriptive error (OUT-03)
- -o flag registered in CLI with timestamp default (OUT-01) - -o flag registered in CLI with timestamp default (OUT-01)
- Snapshot slice accumulator ready for Phase 3 wiring
- Full test suite passes: `CGO_ENABLED=1 go test ./...` - Full test suite passes: `CGO_ENABLED=1 go test ./...`
- Complete Phase 2 audio pipeline validated end-to-end against synthetic data - Complete Phase 2 audio pipeline validated end-to-end against synthetic data
</success_criteria> </success_criteria>
@@ -0,0 +1,97 @@
---
phase: 2
slug: audio-synthesis-engine
status: draft
nyquist_compliant: true
wave_0_complete: true
tdd_model: co-creation
created: 2026-03-26
---
# Phase 2 — Validation Strategy
> Per-phase validation contract for feedback sampling during execution.
---
## Test Infrastructure
| Property | Value |
|----------|-------|
| **Framework** | go test (stdlib) |
| **Config file** | none — existing Go test infrastructure |
| **Quick run command** | `go test ./synth/... ./encode/...` |
| **Full suite command** | `go test ./...` |
| **Estimated runtime** | ~5 seconds |
---
## TDD Model
This phase uses **co-creation TDD**: tests are written within the same task as the implementation, following RED-GREEN-REFACTOR within each task. All TDD tasks are marked with `tdd="true"` in their plan XML. Test files are created as part of the task, not as a separate Wave 0 plan.
This is explicitly chosen over pre-existing stub TDD because:
1. Each task's `<behavior>` block defines expected test cases before implementation begins
2. The executor writes tests FIRST (RED), then implementation (GREEN) within the same task
3. No test file exists before the task starts — the task creates both test and implementation
Wave 0 requirements are limited to environment/tooling setup (gcc, ffprobe, go-lame dependency), handled by Plan 01 Task 1.
---
## Sampling Rate
- **After every task commit:** Run `go test ./synth/... ./encode/...`
- **After every plan wave:** Run `go test ./...`
- **Before `/gsd:verify-work`:** Full suite must be green
- **Max feedback latency:** 5 seconds
---
## Per-Task Verification Map
| Task ID | Plan | Wave | Requirement | Test Type | Automated Command | TDD | Status |
|---------|------|------|-------------|-----------|-------------------|-----|--------|
| 02-01-01 | 01 | 1 | SYNTH-01 | setup | `go version && gcc --version && ffprobe -version && grep "go-lame" go.mod && CGO_ENABLED=1 go build ./...` | n/a | ⬜ pending |
| 02-01-02 | 01 | 1 | SYNTH-01, SYNTH-02 | unit | `cd /home/dev/workspace/yoloyolo && go test ./synth/... -v -count=1` | co-creation | ⬜ pending |
| 02-02-01 | 02 | 2 | SYNTH-03 | unit | `cd /home/dev/workspace/yoloyolo && go test ./synth/... -run "TestPan\|TestStereo\|TestClamp" -v -count=1` | co-creation | ⬜ pending |
| 02-02-02 | 02 | 2 | SYNTH-03 | unit | `cd /home/dev/workspace/yoloyolo && go test ./synth/... -run "TestNewBank\|TestRenderWindow\|TestMixerNoClip\|TestStereoPan\|TestMultipleWindows" -v -count=1` | co-creation | ⬜ pending |
| 02-03-01 | 03 | 3 | OUT-02, OUT-03 | integration | `cd /home/dev/workspace/yoloyolo && CGO_ENABLED=1 go test ./encode/... -v -count=1` | co-creation | ⬜ pending |
| 02-03-02 | 03 | 3 | OUT-01 | build | `cd /home/dev/workspace/yoloyolo && go build -o /dev/null ./cmd/netsynth/ && go run ./cmd/netsynth/ --help 2>&1 \| grep -q "\-o.*output" && echo "OK"` | n/a | ⬜ pending |
*Status: ⬜ pending · ✅ green · ❌ red · ⚠️ flaky*
---
## Wave 0 Requirements
- [x] `gcc` — C compiler required for go-lame CGo compilation (Plan 01, Task 1)
- [x] `ffprobe` — MP3 validation in acceptance tests (Plan 01, Task 1)
- [x] `go get github.com/sjzar/go-lame@v0.0.9` — MP3 encoding dependency (Plan 01, Task 1)
- [x] `go-audio/wav`**Skipped.** Per CONTEXT.md Claude's Discretion grant; write PCM bytes directly to LameWriter (CLAUDE.md updated).
*Test stubs are co-created with implementation in each TDD task (see TDD Model section above).*
---
## Manual-Only Verifications
| Behavior | Requirement | Why Manual | Test Instructions |
|----------|-------------|------------|-------------------|
| Perceptually distinct drone tones per traffic class | SYNTH-01 | Subjective audio quality | Play output MP3, verify each class sounds distinct |
| Amplitude rises/falls audibly with traffic volume | SYNTH-02 | Subjective perception | Listen for volume changes across windows with varying traffic |
| Stereo panning creates spatial separation | SYNTH-03 | Subjective audio quality | Listen with headphones, verify bass center and highs spread |
---
## Validation Sign-Off
- [x] All tasks have `<automated>` verify commands matching plan blocks
- [x] Sampling continuity: no 3 consecutive tasks without automated verify (all tasks have automated verify)
- [x] Wave 0 covers environment/tooling setup (Plan 01, Task 1)
- [x] Co-creation TDD model documented; test expectations defined in `<behavior>` blocks
- [x] No watch-mode flags
- [x] Feedback latency < 5s
- [x] `nyquist_compliant: true` set in frontmatter
**Approval:** ready
+1 -1
View File
@@ -30,7 +30,7 @@ A Go CLI tool that captures live network traffic on an interface, clusters and c
| Library | Version | Purpose | When to Use | | Library | Version | Purpose | When to Use |
|---------|---------|---------|-------------| |---------|---------|---------|-------------|
| `github.com/muesli/kmeans` | v0.3.1 | K-means clustering for unrecognized traffic patterns | Use to auto-cluster packets that don't match known protocol rules. Feed feature vectors: [port, protocol_num, packet_size_bin, direction]. Last release July 2022 but mathematically stable; the algorithm doesn't change. Alternatively, implement a simple incremental classifier directly (see Architecture notes below). | | `github.com/muesli/kmeans` | v0.3.1 | K-means clustering for unrecognized traffic patterns | Use to auto-cluster packets that don't match known protocol rules. Feed feature vectors: [port, protocol_num, packet_size_bin, direction]. Last release July 2022 but mathematically stable; the algorithm doesn't change. Alternatively, implement a simple incremental classifier directly (see Architecture notes below). |
| `github.com/go-audio/wav` | latest | WAV file I/O as intermediate format | Use to write synthesized PCM as WAV before MP3 encoding pass. "Battle tested" per maintainer. Simplifies the PCM → encoder pipeline: synthesize float64 samples → write WAV → re-read as PCM → LAME encode. | | `github.com/go-audio/wav` | latest | WAV file I/O as intermediate format | **Optional.** Originally recommended for PCM intermediate buffering, but Phase 2 research found that go-audio/wav requires `io.WriteSeeker` (which `bytes.Buffer` does not satisfy) and adds unnecessary complexity. The simpler approach is writing interleaved int16 PCM bytes directly to go-lame's `LameWriter.Write()`. Skip unless a WAV debug output feature is needed. Decision made under CONTEXT.md Claude's Discretion grant for "WAV intermediate format usage." |
| `golang.org/x/sys/unix` | stdlib | Raw socket / CAP_NET_RAW privilege checks | Use for detecting if the process has required privileges and for signaling (SIGINT for clean shutdown). Part of Go extended stdlib — no external version pinning needed. | | `golang.org/x/sys/unix` | stdlib | Raw socket / CAP_NET_RAW privilege checks | Use for detecting if the process has required privileges and for signaling (SIGINT for clean shutdown). Part of Go extended stdlib — no external version pinning needed. |
### Development Tools ### Development Tools
| Tool | Purpose | Notes | | Tool | Purpose | Notes |