From 000e6a38133a2074b39ffad6c329bd6857f81468 Mon Sep 17 00:00:00 2001 From: Markus Graf Date: Fri, 27 Mar 2026 08:50:37 +0100 Subject: [PATCH] docs(08): create phase plan --- .planning/ROADMAP.md | 8 +- .../08-01-PLAN.md | 214 ++++++++++++++++++ 2 files changed, 219 insertions(+), 3 deletions(-) create mode 100644 .planning/phases/08-test-and-constant-cleanup/08-01-PLAN.md diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index 6bc14de..3d6eabd 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -35,7 +35,7 @@ Full details: `.planning/milestones/v1.1-ROADMAP.md` **Milestone Goal:** Expand traffic classification with grouped protocol families that share recognizable sound signatures — from 14 classes to ~35, organized into frequency bands by family. -- [ ] **Phase 8: Test and Constant Cleanup** - Remove stale constants and update test bounds that would block all subsequent v1.2 work +- [ ] **Phase 8: Test and Constant Cleanup** - 1 plan — Remove stale constants and update test bounds that would block all subsequent v1.2 work - [ ] **Phase 9: Frequency Design and Group Architecture** - Design complete Hz allocation for all ~35 classes in family bands and add Group field to FreqConfig - [ ] **Phase 10: Classification Layer** - Add ~21 new TrafficClass constants and port rules covering all new protocol families - [ ] **Phase 11: Synthesis and Config Layer** - Add ClassFreqConfigs entries for all new classes, update auto-assign range, and add group-header output to --print-config @@ -50,7 +50,9 @@ Full details: `.planning/milestones/v1.1-ROADMAP.md` 1. `go test ./...` passes on main with no modifications to the new v1.2 code path 2. The stale `NumLayers`/`GainPerLayer` exported constant no longer exists in the synth package — callers cannot accidentally use it 3. `TestFrequenciesInRange` accepts the new extended Hz range without manual test surgery when new classes are added in Phase 10 -**Plans**: TBD +**Plans:** 1 plan +Plans: +- [ ] 08-01-PLAN.md — Delete stale constants, future-proof test bounds, rename/consolidate tests ### Phase 9: Frequency Design and Group Architecture **Goal**: A complete, documented frequency allocation table for all ~35 traffic classes exists and the FreqConfig struct carries a Group field — design decisions are locked in before any protocol code is written @@ -97,7 +99,7 @@ Full details: `.planning/milestones/v1.1-ROADMAP.md` | 5. Waveform Types and Bank Decoupling | v1.1 | 2/2 | Complete | 2026-03-26 | | 6. Config Package and Sound Overrides | v1.1 | 2/2 | Complete | 2026-03-26 | | 7. Custom Rules and Print-Config | v1.1 | 2/2 | Complete | 2026-03-26 | -| 8. Test and Constant Cleanup | v1.2 | 0/? | Not started | - | +| 8. Test and Constant Cleanup | v1.2 | 0/1 | Planning | - | | 9. Frequency Design and Group Architecture | v1.2 | 0/? | Not started | - | | 10. Classification Layer | v1.2 | 0/? | Not started | - | | 11. Synthesis and Config Layer | v1.2 | 0/? | Not started | - | diff --git a/.planning/phases/08-test-and-constant-cleanup/08-01-PLAN.md b/.planning/phases/08-test-and-constant-cleanup/08-01-PLAN.md new file mode 100644 index 0000000..6659f7f --- /dev/null +++ b/.planning/phases/08-test-and-constant-cleanup/08-01-PLAN.md @@ -0,0 +1,214 @@ +--- +phase: 08-test-and-constant-cleanup +plan: 01 +type: execute +wave: 1 +depends_on: [] +files_modified: + - synth/config.go + - synth/config_test.go +autonomous: true +requirements: + - CLEAN-01 +must_haves: + truths: + - "NumLayers and GainPerLayer constants do not exist in the synth package" + - "go test ./... passes with zero failures after all edits" + - "TestFrequenciesInRange accepts any BaseHz in (0, Nyquist) without manual test surgery" + - "TestNumLayersMatchesAllClasses is renamed to TestClassFreqConfigsMatchAllClasses" + artifacts: + - path: "synth/config.go" + provides: "Cleaned constant block without NumLayers or GainPerLayer" + contains: "WhisperFloor" + - path: "synth/config_test.go" + provides: "Future-proof test assertions" + contains: "TestClassFreqConfigsMatchAllClasses" + key_links: + - from: "synth/bank.go" + to: "synth/config.go" + via: "gainPerLayer computed dynamically in NewBank — no longer any static constant to conflict with" + pattern: "1\\.0 / float64\\(len\\(cfgs\\)\\)" + - from: "synth/config_test.go" + to: "synth/config.go" + via: "TestFrequenciesInRange validates BaseHz against SampleRate-derived Nyquist" + pattern: "float64\\(synth\\.SampleRate\\)" +--- + + +Remove stale exported constants and hardcoded test bounds from the synth package so that subsequent v1.2 phases can add new traffic classes and frequencies without triggering false CI failures. + +Purpose: Phase 8 is the gatekeeper for all v1.2 work. NumLayers=14 is dead code (NewBank computes gain dynamically), and TestFrequenciesInRange's [60, 1100] bound will reject any new class above 1100 Hz. Both must be cleaned up before Phase 9-11 proceed. + +Output: Two edited files (synth/config.go, synth/config_test.go) with all tests green. + + + +@$HOME/.claude/get-shit-done/workflows/execute-plan.md +@$HOME/.claude/get-shit-done/templates/summary.md + + + +@.planning/PROJECT.md +@.planning/ROADMAP.md +@.planning/STATE.md +@.planning/phases/08-test-and-constant-cleanup/08-CONTEXT.md +@.planning/phases/08-test-and-constant-cleanup/08-RESEARCH.md + + + + +From synth/config.go (current constant block, lines 5-12): +```go +const ( + SampleRate = 44100 // D-13: CD quality + WindowMs = 500 // matches aggregate.DefaultWindowMs + SamplesPerWindow = SampleRate * WindowMs / 1000 // 22050 + NumLayers = 14 // <-- DELETE per D-01 + GainPerLayer = 1.0 / float64(NumLayers) // D-10: ~0.0714 <-- DELETE per D-01 + WhisperFloor = 0.03 // D-08/D-09: 3% of max amplitude +) +``` + +From synth/bank.go (line 21 — confirms constants are dead code): +```go +gainPerLayer: 1.0 / float64(len(cfgs)), // dynamic computation, no constant needed +``` + +From synth/config_test.go (current test functions to modify): +```go +// Lines 18-25: TestFrequenciesInRange — hardcoded [60, 1100] to replace +// Lines 53-59: TestClassFreqConfigsComplete — duplicate of TestAllClassesHaveConfig +// Lines 61-66: TestNumLayersMatchesAllClasses — rename to TestClassFreqConfigsMatchAllClasses +``` + + + + + + + Task 1: Delete stale NumLayers and GainPerLayer constants from synth/config.go + synth/config.go + + - synth/config.go (see current constant block at lines 5-12) + - synth/bank.go (line 21 confirms gainPerLayer is computed dynamically) + + +Per D-01: Delete lines 9-10 from synth/config.go — the `NumLayers = 14` and `GainPerLayer = 1.0 / float64(NumLayers)` constants. + +The resulting constant block must be: + +```go +const ( + SampleRate = 44100 // D-13: CD quality + WindowMs = 500 // matches aggregate.DefaultWindowMs + SamplesPerWindow = SampleRate * WindowMs / 1000 // 22050 + WhisperFloor = 0.03 // D-08/D-09: 3% of max amplitude +) +``` + +Do NOT modify any other lines in config.go. Do NOT touch bank.go — NewBank's dynamic `1.0 / float64(len(cfgs))` is already correct. + +Optionally, add a traceability comment to synth/bank.go line 21: +`gainPerLayer: 1.0 / float64(len(cfgs)), // D-10: 1/N so all layers at full amplitude sum to 1.0` +This is low-priority — skip if it feels like noise. + + + cd /home/dev/workspace/yoloyolo && grep -n "NumLayers\|GainPerLayer" synth/config.go; echo "EXIT:$?" + + + - `grep -c "NumLayers" synth/config.go` returns 0 + - `grep -c "GainPerLayer" synth/config.go` returns 0 + - `synth/config.go` still contains `SampleRate = 44100` + - `synth/config.go` still contains `WhisperFloor = 0.03` + - `go build ./synth/...` exits 0 (no compilation errors from removing the constants) + + NumLayers and GainPerLayer constants no longer exist in synth/config.go. The constant block contains only SampleRate, WindowMs, SamplesPerWindow, and WhisperFloor. Code compiles cleanly. + + + + Task 2: Update synth/config_test.go — future-proof frequency bounds, rename test, remove duplicate + synth/config_test.go + + - synth/config_test.go (full file — see all 6 test functions) + - synth/config.go (after Task 1 edits — confirm SampleRate is exported) + + +Three changes to synth/config_test.go: + +**Change 1 (per D-02):** Replace the body of `TestFrequenciesInRange` (lines 18-25) with Nyquist-based validation. The new function body: + +```go +func TestFrequenciesInRange(t *testing.T) { + const nyquist = float64(synth.SampleRate) / 2.0 // 22050 Hz + for class, cfg := range synth.ClassFreqConfigs { + if cfg.BaseHz <= 0 { + t.Errorf("class %q BaseHz=%.1f must be positive", class, cfg.BaseHz) + } + if cfg.BaseHz >= nyquist { + t.Errorf("class %q BaseHz=%.1f exceeds Nyquist (%.1f Hz)", class, cfg.BaseHz, nyquist) + } + } +} +``` + +This accepts any BaseHz in (0, 22050) — no manual edit needed when Phase 10 adds classes above 1100 Hz. + +**Change 2 (per D-03):** Rename `TestNumLayersMatchesAllClasses` (line 61) to `TestClassFreqConfigsMatchAllClasses`. Keep the function body identical: + +```go +func TestClassFreqConfigsMatchAllClasses(t *testing.T) { + if len(synth.ClassFreqConfigs) != len(classify.AllClasses()) { + t.Errorf("ClassFreqConfigs has %d entries but AllClasses() has %d entries", + len(synth.ClassFreqConfigs), len(classify.AllClasses())) + } +} +``` + +**Change 3 (Claude's discretion — consolidation):** Delete `TestClassFreqConfigsComplete` (lines 53-59) entirely. It is a semantic duplicate of `TestAllClassesHaveConfig` (lines 10-16) — both iterate `AllClasses()` and check for a map entry. Removing it leaves three non-overlapping tests: +- `TestAllClassesHaveConfig` — every AllClasses() member has a map entry +- `TestClassFreqConfigsMatchAllClasses` — count parity (catches extra entries) +- `TestFrequenciesInRange` — all BaseHz positive and below Nyquist + +The remaining tests (`TestFrequenciesUnique`, `TestHarmonicsNonEmpty`, `TestPanPositionsInRange`) are untouched. + + + cd /home/dev/workspace/yoloyolo && go test ./synth/... -v -count=1 2>&1 | head -40 + + + - `grep -c "TestNumLayersMatchesAllClasses" synth/config_test.go` returns 0 + - `grep -c "TestClassFreqConfigsMatchAllClasses" synth/config_test.go` returns 1 + - `grep -c "TestClassFreqConfigsComplete" synth/config_test.go` returns 0 + - `grep "nyquist" synth/config_test.go` returns at least one match + - `grep "1100" synth/config_test.go` returns 0 matches (hardcoded bound removed) + - `go test ./synth/... -run TestFrequenciesInRange` exits 0 + - `go test ./synth/... -run TestClassFreqConfigsMatchAllClasses` exits 0 + - `go test ./...` exits 0 (full suite green) + + TestFrequenciesInRange uses Nyquist-based validation (no hardcoded upper bound). TestNumLayersMatchesAllClasses renamed to TestClassFreqConfigsMatchAllClasses. Duplicate TestClassFreqConfigsComplete removed. Full test suite passes. + + + + + +After both tasks complete: + +1. `grep -rn "NumLayers\|GainPerLayer" synth/*.go` — zero matches in production and test code +2. `grep -n "1100" synth/config_test.go` — zero matches (hardcoded bound gone) +3. `go test ./...` — all packages pass with zero failures +4. `go test ./synth/... -run TestFrequenciesInRange` — passes +5. `go test ./synth/... -run TestClassFreqConfigsMatchAllClasses` — passes +6. `go test ./synth/... -run TestClassFreqConfigsComplete` — no such test (removed) + + + +- NumLayers and GainPerLayer constants deleted from synth/config.go +- TestFrequenciesInRange validates against Nyquist (22050 Hz), not hardcoded 1100 +- TestNumLayersMatchesAllClasses renamed to TestClassFreqConfigsMatchAllClasses +- Duplicate TestClassFreqConfigsComplete removed +- `go test ./...` passes with zero failures +- Adding a new class with BaseHz=2000 in a future phase would NOT require editing any test + + + +After completion, create `.planning/phases/08-test-and-constant-cleanup/08-01-SUMMARY.md` +