docs(09): create phase plan
This commit is contained in:
@@ -36,7 +36,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.
|
||||
|
||||
- [x] **Phase 8: Test and Constant Cleanup** - 1 plan — Remove stale constants and update test bounds that would block all subsequent v1.2 work (completed 2026-03-27)
|
||||
- [ ] **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 9: Frequency Design and Group Architecture** - 2 plans — 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
|
||||
|
||||
@@ -63,8 +63,10 @@ Plans:
|
||||
2. Every within-family pair of frequencies satisfies at least a major second interval (ratio 1.122), verifiable by inspection of the table
|
||||
3. The `autoAssignFreq` base for user-defined custom classes is set above all built-in frequencies, with no collision possible
|
||||
4. `FreqConfig` has a `Group` string field and all existing `ClassFreqConfigs` entries compile with the new struct shape
|
||||
**Plans**: TBD
|
||||
**UI hint**: no
|
||||
**Plans:** 2 plans
|
||||
Plans:
|
||||
- [ ] 09-01-PLAN.md — Add Group field to FreqConfig, rebalance ClassFreqConfigs to major-second ladder
|
||||
- [ ] 09-02-PLAN.md — Update auto-assign range from [1200,2350] to [2500,4000] Hz
|
||||
|
||||
### Phase 10: Classification Layer
|
||||
**Goal**: All new protocol families are classified — ~21 new TrafficClass constants exist, AllClasses() covers them, and DefaultRules maps all new ports to their classes
|
||||
@@ -100,6 +102,6 @@ Plans:
|
||||
| 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 | 1/1 | Complete | 2026-03-27 |
|
||||
| 9. Frequency Design and Group Architecture | v1.2 | 0/? | Not started | - |
|
||||
| 9. Frequency Design and Group Architecture | v1.2 | 0/2 | Not started | - |
|
||||
| 10. Classification Layer | v1.2 | 0/? | Not started | - |
|
||||
| 11. Synthesis and Config Layer | v1.2 | 0/? | Not started | - |
|
||||
|
||||
@@ -0,0 +1,364 @@
|
||||
---
|
||||
phase: 09-frequency-design-and-group-architecture
|
||||
plan: 01
|
||||
type: execute
|
||||
wave: 1
|
||||
depends_on: []
|
||||
files_modified:
|
||||
- synth/config.go
|
||||
- synth/config_test.go
|
||||
autonomous: true
|
||||
requirements:
|
||||
- FREQ-01
|
||||
- FREQ-02
|
||||
- FREQ-03
|
||||
- GRP-01
|
||||
- GRP-04
|
||||
|
||||
must_haves:
|
||||
truths:
|
||||
- "FreqConfig struct has a Group string field"
|
||||
- "All 14 existing ClassFreqConfigs entries have non-empty Group values"
|
||||
- "All existing classes are redistributed to new Hz values per the major-second ladder (65-1375 Hz range)"
|
||||
- "Within-family adjacent pairs satisfy at least a major second interval (ratio >= 1.122)"
|
||||
- "Non-Unknown family entries use WaveformPresetHarmonics instead of hand-tuned slices"
|
||||
- "Unknown family entries retain hand-tuned dissonant harmonics {1,1.0},{2,0.8},{3,0.4}"
|
||||
- "go test ./synth/... passes with all tests green"
|
||||
artifacts:
|
||||
- path: "synth/config.go"
|
||||
provides: "FreqConfig with Group field, rebalanced ClassFreqConfigs map"
|
||||
contains: "Group string"
|
||||
- path: "synth/config_test.go"
|
||||
provides: "TestGroupFieldPopulated, updated TestHarmonicsNonEmpty"
|
||||
contains: "TestGroupFieldPopulated"
|
||||
key_links:
|
||||
- from: "synth/config.go"
|
||||
to: "classify/types.go"
|
||||
via: "ClassFreqConfigs map keys reference classify.TrafficClass constants"
|
||||
pattern: "classify\\.Class"
|
||||
---
|
||||
|
||||
<objective>
|
||||
Add Group field to FreqConfig and rebalance all 14 existing ClassFreqConfigs entries to the new major-second frequency ladder with family-band organization, waveform-per-family assignments, and Group string values.
|
||||
|
||||
Purpose: Lock the frequency design and group architecture so Phase 10 can add new TrafficClass constants that slot directly into the designed frequency bands. Per D-01, this is a full rebalance -- existing v1.0/v1.1 Hz values are NOT frozen.
|
||||
|
||||
Output: Updated synth/config.go with Group field and rebalanced map, updated synth/config_test.go with new/fixed tests.
|
||||
</objective>
|
||||
|
||||
<execution_context>
|
||||
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
|
||||
@$HOME/.claude/get-shit-done/templates/summary.md
|
||||
</execution_context>
|
||||
|
||||
<context>
|
||||
@.planning/PROJECT.md
|
||||
@.planning/ROADMAP.md
|
||||
@.planning/STATE.md
|
||||
@.planning/phases/09-frequency-design-and-group-architecture/09-CONTEXT.md
|
||||
@.planning/phases/09-frequency-design-and-group-architecture/09-RESEARCH.md
|
||||
|
||||
<interfaces>
|
||||
<!-- From synth/config.go — current FreqConfig struct (line 66-71) -->
|
||||
```go
|
||||
type FreqConfig struct {
|
||||
BaseHz float64
|
||||
Harmonics []HarmonicDef
|
||||
Pan float64
|
||||
WaveformType WaveformType
|
||||
}
|
||||
```
|
||||
|
||||
<!-- From synth/config.go — WaveformType constants (line 14-22) -->
|
||||
```go
|
||||
const (
|
||||
WaveformCustom WaveformType = iota
|
||||
WaveformSine
|
||||
WaveformSquare
|
||||
WaveformSawtooth
|
||||
WaveformTriangle
|
||||
)
|
||||
```
|
||||
|
||||
<!-- From synth/config.go — WaveformPresetHarmonics signature (line 27) -->
|
||||
```go
|
||||
func WaveformPresetHarmonics(wt WaveformType, baseHz float64, sampleRate int) []HarmonicDef
|
||||
```
|
||||
|
||||
<!-- From classify/types.go — existing TrafficClass constants used as map keys -->
|
||||
```
|
||||
ClassICMP, ClassDNS, ClassHTTPS, ClassHTTP, ClassSSH, ClassSMTP,
|
||||
ClassNTP, ClassDHCP, ClassOtherTCP, ClassOtherUDP,
|
||||
ClassUnknown1, ClassUnknown2, ClassUnknown3, ClassUnknown4
|
||||
```
|
||||
</interfaces>
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: Add Group field to FreqConfig and rebalance ClassFreqConfigs</name>
|
||||
<files>synth/config.go</files>
|
||||
<read_first>
|
||||
- synth/config.go (current FreqConfig struct at line 66, ClassFreqConfigs map at line 76)
|
||||
- .planning/phases/09-frequency-design-and-group-architecture/09-RESEARCH.md (full allocation table, code examples)
|
||||
</read_first>
|
||||
<action>
|
||||
1. Add `Group string` field to the `FreqConfig` struct after the `WaveformType` field:
|
||||
|
||||
```go
|
||||
type FreqConfig struct {
|
||||
BaseHz float64
|
||||
Harmonics []HarmonicDef
|
||||
Pan float64
|
||||
WaveformType WaveformType
|
||||
Group string // sound family: "Infrastructure", "Web", "Mail", etc.
|
||||
}
|
||||
```
|
||||
|
||||
2. Add a frequency allocation table comment block above ClassFreqConfigs documenting all 32 designed slots (per FREQ-03). This is the authoritative design reference. The comment should list:
|
||||
|
||||
```
|
||||
// Frequency Allocation Table (Phase 9 design — major-second ladder, 65-2449 Hz)
|
||||
//
|
||||
// Slot Hz Class Group Waveform Pan
|
||||
// 0 65 ICMP Infrastructure Triangle -0.3
|
||||
// 1 73 NTP Infrastructure Triangle -0.1
|
||||
// 2 82 DHCP Infrastructure Triangle 0.1
|
||||
// 3 93 mDNS Infrastructure Triangle 0.3 (Phase 10)
|
||||
// 4 105 SSDP Infrastructure Triangle -0.2 (Phase 10)
|
||||
// 5 118 SNMP Infrastructure Triangle 0.2 (Phase 10)
|
||||
// 6 133 DNS Infrastructure Triangle 0.0
|
||||
// 7 150 HTTPS Web Sawtooth -0.4
|
||||
// 8 169 HTTP Web Sawtooth -0.3
|
||||
// 9 190 HTTP3 Web Sawtooth -0.2 (Phase 10)
|
||||
// 10 214 SMTP Mail Triangle 0.2
|
||||
// 11 241 IMAP Mail Triangle 0.3 (Phase 10)
|
||||
// 12 271 POP3 Mail Triangle 0.4 (Phase 10)
|
||||
// 13 305 SMTP-sub Mail Triangle 0.5 (Phase 10)
|
||||
// 14 343 SSH Remote Access Square -0.7
|
||||
// 15 385 RDP Remote Access Square -0.6 (Phase 10)
|
||||
// 16 432 Telnet Remote Access Square -0.5 (Phase 10)
|
||||
// 17 485 VNC Remote Access Square -0.4 (Phase 10)
|
||||
// 18 545 FTP File Transfer Square 0.5 (Phase 10)
|
||||
// 19 612 SMB File Transfer Square 0.6 (Phase 10)
|
||||
// 20 687 TFTP File Transfer Square 0.7 (Phase 10)
|
||||
// 21 771 unknown-1 Unknown Custom -0.9
|
||||
// 22 866 unknown-2 Unknown Custom 0.9
|
||||
// 23 972 unknown-3 Unknown Custom -0.7
|
||||
// 24 1091 unknown-4 Unknown Custom 0.7
|
||||
// 25 1225 other-TCP Unknown Custom -0.5
|
||||
// 26 1375 other-UDP Unknown Custom 0.5
|
||||
// 27 1543 MySQL Database Sawtooth -0.4 (Phase 10)
|
||||
// 28 1732 PostgreSQL Database Sawtooth -0.2 (Phase 10)
|
||||
// 29 1944 Redis Database Sawtooth 0.2 (Phase 10)
|
||||
// 30 2182 MongoDB Database Sawtooth 0.4 (Phase 10)
|
||||
// 31 2449 SIP VoIP Sine 0.0 (Phase 10)
|
||||
//
|
||||
// Auto-assign range: [2500, 4000] Hz (see config/config.go)
|
||||
```
|
||||
|
||||
3. Replace the entire `ClassFreqConfigs` map literal with the rebalanced entries for the 14 existing classes. Use `WaveformPresetHarmonics` for non-Unknown entries (per D-08/D-09). Unknown entries retain hand-tuned harmonics.
|
||||
|
||||
Exact entries (all 14):
|
||||
|
||||
```go
|
||||
var ClassFreqConfigs = map[classify.TrafficClass]FreqConfig{
|
||||
// --- Infrastructure (Triangle, 65-133 Hz) ---
|
||||
classify.ClassICMP: {
|
||||
BaseHz: 65.0,
|
||||
WaveformType: WaveformTriangle,
|
||||
Harmonics: WaveformPresetHarmonics(WaveformTriangle, 65.0, SampleRate),
|
||||
Pan: -0.3,
|
||||
Group: "Infrastructure",
|
||||
},
|
||||
classify.ClassNTP: {
|
||||
BaseHz: 73.0,
|
||||
WaveformType: WaveformTriangle,
|
||||
Harmonics: WaveformPresetHarmonics(WaveformTriangle, 73.0, SampleRate),
|
||||
Pan: -0.1,
|
||||
Group: "Infrastructure",
|
||||
},
|
||||
classify.ClassDHCP: {
|
||||
BaseHz: 82.0,
|
||||
WaveformType: WaveformTriangle,
|
||||
Harmonics: WaveformPresetHarmonics(WaveformTriangle, 82.0, SampleRate),
|
||||
Pan: 0.1,
|
||||
Group: "Infrastructure",
|
||||
},
|
||||
classify.ClassDNS: {
|
||||
BaseHz: 133.0,
|
||||
WaveformType: WaveformTriangle,
|
||||
Harmonics: WaveformPresetHarmonics(WaveformTriangle, 133.0, SampleRate),
|
||||
Pan: 0.0,
|
||||
Group: "Infrastructure",
|
||||
},
|
||||
// --- Web (Sawtooth, 150-190 Hz) ---
|
||||
classify.ClassHTTPS: {
|
||||
BaseHz: 150.0,
|
||||
WaveformType: WaveformSawtooth,
|
||||
Harmonics: WaveformPresetHarmonics(WaveformSawtooth, 150.0, SampleRate),
|
||||
Pan: -0.4,
|
||||
Group: "Web",
|
||||
},
|
||||
classify.ClassHTTP: {
|
||||
BaseHz: 169.0,
|
||||
WaveformType: WaveformSawtooth,
|
||||
Harmonics: WaveformPresetHarmonics(WaveformSawtooth, 169.0, SampleRate),
|
||||
Pan: -0.3,
|
||||
Group: "Web",
|
||||
},
|
||||
// --- Mail (Triangle, 214 Hz) ---
|
||||
classify.ClassSMTP: {
|
||||
BaseHz: 214.0,
|
||||
WaveformType: WaveformTriangle,
|
||||
Harmonics: WaveformPresetHarmonics(WaveformTriangle, 214.0, SampleRate),
|
||||
Pan: 0.2,
|
||||
Group: "Mail",
|
||||
},
|
||||
// --- Remote Access (Square, 343 Hz) ---
|
||||
classify.ClassSSH: {
|
||||
BaseHz: 343.0,
|
||||
WaveformType: WaveformSquare,
|
||||
Harmonics: WaveformPresetHarmonics(WaveformSquare, 343.0, SampleRate),
|
||||
Pan: -0.7,
|
||||
Group: "Remote Access",
|
||||
},
|
||||
// --- Unknown (Custom harmonics, 771-1375 Hz) ---
|
||||
classify.ClassUnknown1: {
|
||||
BaseHz: 771.0,
|
||||
Harmonics: []HarmonicDef{{1, 1.0}, {2, 0.8}, {3, 0.4}},
|
||||
Pan: -0.9,
|
||||
Group: "Unknown",
|
||||
},
|
||||
classify.ClassUnknown2: {
|
||||
BaseHz: 866.0,
|
||||
Harmonics: []HarmonicDef{{1, 1.0}, {2, 0.8}, {3, 0.4}},
|
||||
Pan: 0.9,
|
||||
Group: "Unknown",
|
||||
},
|
||||
classify.ClassUnknown3: {
|
||||
BaseHz: 972.0,
|
||||
Harmonics: []HarmonicDef{{1, 1.0}, {2, 0.8}, {3, 0.4}},
|
||||
Pan: -0.7,
|
||||
Group: "Unknown",
|
||||
},
|
||||
classify.ClassUnknown4: {
|
||||
BaseHz: 1091.0,
|
||||
Harmonics: []HarmonicDef{{1, 1.0}, {2, 0.8}, {3, 0.4}},
|
||||
Pan: 0.7,
|
||||
Group: "Unknown",
|
||||
},
|
||||
classify.ClassOtherTCP: {
|
||||
BaseHz: 1225.0,
|
||||
Harmonics: []HarmonicDef{{1, 1.0}, {2, 0.8}, {3, 0.4}},
|
||||
Pan: -0.5,
|
||||
Group: "Unknown",
|
||||
},
|
||||
classify.ClassOtherUDP: {
|
||||
BaseHz: 1375.0,
|
||||
Harmonics: []HarmonicDef{{1, 1.0}, {2, 0.8}, {3, 0.4}},
|
||||
Pan: 0.5,
|
||||
Group: "Unknown",
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
IMPORTANT: Unknown family entries (ClassUnknown1-4, ClassOtherTCP, ClassOtherUDP) must NOT set WaveformType — leave it as zero value (WaveformCustom) so bank.go uses the stored Harmonics. Do NOT call WaveformPresetHarmonics for these entries.
|
||||
|
||||
IMPORTANT: Do NOT remove the old `// Frequencies use musical intervals...` comment — replace it with the new allocation table comment.
|
||||
</action>
|
||||
<verify>
|
||||
<automated>cd /home/dev/workspace/yoloyolo && go build ./synth/...</automated>
|
||||
</verify>
|
||||
<acceptance_criteria>
|
||||
- synth/config.go contains `Group string` inside the FreqConfig struct
|
||||
- synth/config.go contains `Group: "Infrastructure"` (at least 4 entries)
|
||||
- synth/config.go contains `Group: "Web"` (at least 2 entries)
|
||||
- synth/config.go contains `Group: "Mail"` (at least 1 entry)
|
||||
- synth/config.go contains `Group: "Remote Access"` (at least 1 entry)
|
||||
- synth/config.go contains `Group: "Unknown"` (at least 6 entries)
|
||||
- synth/config.go contains `BaseHz: 65.0` for ClassICMP
|
||||
- synth/config.go contains `BaseHz: 133.0` for ClassDNS
|
||||
- synth/config.go contains `BaseHz: 150.0` for ClassHTTPS
|
||||
- synth/config.go contains `BaseHz: 343.0` for ClassSSH
|
||||
- synth/config.go contains `WaveformPresetHarmonics(WaveformTriangle` for Infrastructure entries
|
||||
- synth/config.go contains `WaveformPresetHarmonics(WaveformSawtooth` for Web entries
|
||||
- synth/config.go contains `WaveformPresetHarmonics(WaveformSquare` for SSH entry
|
||||
- synth/config.go contains `// Frequency Allocation Table` comment block
|
||||
- Unknown entries do NOT contain `WaveformPresetHarmonics` — they use literal `[]HarmonicDef{{1, 1.0}, {2, 0.8}, {3, 0.4}}`
|
||||
- `go build ./synth/...` exits 0
|
||||
</acceptance_criteria>
|
||||
<done>FreqConfig has Group field, all 14 ClassFreqConfigs entries have correct Hz/waveform/group per allocation table, code compiles</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: Update synth tests — add TestGroupFieldPopulated, fix TestHarmonicsNonEmpty</name>
|
||||
<files>synth/config_test.go</files>
|
||||
<read_first>
|
||||
- synth/config_test.go (current test file — TestHarmonicsNonEmpty at line 40 checks len >= 2)
|
||||
- synth/config.go (the updated file from Task 1 — verify Group field exists)
|
||||
</read_first>
|
||||
<action>
|
||||
1. Add `TestGroupFieldPopulated` test function after the existing tests. This test iterates all ClassFreqConfigs entries and fails if any have an empty Group string:
|
||||
|
||||
```go
|
||||
func TestGroupFieldPopulated(t *testing.T) {
|
||||
for class, cfg := range synth.ClassFreqConfigs {
|
||||
if cfg.Group == "" {
|
||||
t.Errorf("class %q has empty Group field in ClassFreqConfigs", class)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. Update `TestHarmonicsNonEmpty` to accept single-harmonic entries. Change the threshold from `< 2` to `< 1`. This is needed because WaveformSine (used by SIP in Phase 10) returns only 1 harmonic. The current 8 non-Unknown entries all use Triangle/Sawtooth/Square which return multiple harmonics, so this change is safe now and future-proofs for Phase 10.
|
||||
|
||||
Change line 42 from:
|
||||
```go
|
||||
if len(cfg.Harmonics) < 2 {
|
||||
t.Errorf("class %q has fewer than 2 harmonics (got %d)", class, len(cfg.Harmonics))
|
||||
```
|
||||
To:
|
||||
```go
|
||||
if len(cfg.Harmonics) < 1 {
|
||||
t.Errorf("class %q has no harmonics (got %d)", class, len(cfg.Harmonics))
|
||||
```
|
||||
|
||||
This addresses Research Open Question 2: pure sine (1 harmonic) is valid, not a bug.
|
||||
</action>
|
||||
<verify>
|
||||
<automated>cd /home/dev/workspace/yoloyolo && go test ./synth/... -v -count=1</automated>
|
||||
</verify>
|
||||
<acceptance_criteria>
|
||||
- synth/config_test.go contains `func TestGroupFieldPopulated(t *testing.T)`
|
||||
- synth/config_test.go contains `cfg.Group == ""`
|
||||
- synth/config_test.go contains `len(cfg.Harmonics) < 1` (NOT `< 2`)
|
||||
- `go test ./synth/... -run TestGroupFieldPopulated` exits 0
|
||||
- `go test ./synth/... -run TestHarmonicsNonEmpty` exits 0
|
||||
- `go test ./synth/...` exits 0 (all tests pass)
|
||||
</acceptance_criteria>
|
||||
<done>TestGroupFieldPopulated catches missing Group values; TestHarmonicsNonEmpty accepts single-harmonic (sine) entries; all synth tests pass</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<verification>
|
||||
- `go build ./synth/...` compiles without errors
|
||||
- `go test ./synth/... -v` passes all tests including new TestGroupFieldPopulated
|
||||
- `grep -c 'Group:' synth/config.go` returns 14 (one per ClassFreqConfigs entry)
|
||||
- `grep 'Group string' synth/config.go` confirms struct field exists
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- FreqConfig struct has Group string field (GRP-04)
|
||||
- All 14 existing ClassFreqConfigs entries have Group values matching their family (GRP-01)
|
||||
- Frequency allocation table comment documents all 32 designed slots (FREQ-03)
|
||||
- All existing classes redistributed to major-second ladder Hz values (FREQ-01)
|
||||
- Within-family spacing satisfies >= 1.122 ratio (FREQ-02)
|
||||
- All synth tests pass including new TestGroupFieldPopulated
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
After completion, create `.planning/phases/09-frequency-design-and-group-architecture/09-01-SUMMARY.md`
|
||||
</output>
|
||||
@@ -0,0 +1,206 @@
|
||||
---
|
||||
phase: 09-frequency-design-and-group-architecture
|
||||
plan: 02
|
||||
type: execute
|
||||
wave: 1
|
||||
depends_on: []
|
||||
files_modified:
|
||||
- config/config.go
|
||||
- config/config_test.go
|
||||
autonomous: true
|
||||
requirements:
|
||||
- FREQ-04
|
||||
|
||||
must_haves:
|
||||
truths:
|
||||
- "autoAssignFreq returns Hz values in [2500, 4000] range, not the old [1200, 2350]"
|
||||
- "Auto-assigned classes cannot collide with any built-in frequency (max built-in is 2449 Hz, auto-assign starts at 2500 Hz)"
|
||||
- "TestAutoFreqAssignment passes with the new range bounds"
|
||||
- "addAutoFreqEntries produces FreqConfig with empty Group (zero value) for user-defined classes"
|
||||
artifacts:
|
||||
- path: "config/config.go"
|
||||
provides: "Updated autoAssignFreq constants"
|
||||
contains: "baseHz = 2500.0"
|
||||
- path: "config/config_test.go"
|
||||
provides: "Updated range assertion"
|
||||
contains: "cfg.BaseHz < 2500.0 || cfg.BaseHz > 4000.0"
|
||||
key_links:
|
||||
- from: "config/config.go"
|
||||
to: "synth/config.go"
|
||||
via: "addAutoFreqEntries creates synth.FreqConfig entries"
|
||||
pattern: "synth\\.FreqConfig"
|
||||
---
|
||||
|
||||
<objective>
|
||||
Update the auto-assign frequency range from [1200, 2350] to [2500, 4000] Hz so custom user-defined classes cannot collide with any built-in frequency. Update the corresponding test assertion.
|
||||
|
||||
Purpose: Per D-04, the auto-assign range must be pushed above all built-in frequencies (max 2449 Hz) to prevent collision. The 51 Hz buffer between 2449 and 2500 guarantees no overlap.
|
||||
|
||||
Output: Updated config/config.go constants, updated config/config_test.go assertion.
|
||||
</objective>
|
||||
|
||||
<execution_context>
|
||||
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
|
||||
@$HOME/.claude/get-shit-done/templates/summary.md
|
||||
</execution_context>
|
||||
|
||||
<context>
|
||||
@.planning/PROJECT.md
|
||||
@.planning/ROADMAP.md
|
||||
@.planning/STATE.md
|
||||
@.planning/phases/09-frequency-design-and-group-architecture/09-CONTEXT.md
|
||||
@.planning/phases/09-frequency-design-and-group-architecture/09-RESEARCH.md
|
||||
|
||||
<interfaces>
|
||||
<!-- From config/config.go — current autoAssignFreq function (lines 208-219) -->
|
||||
```go
|
||||
func autoAssignFreq(className string) float64 {
|
||||
h := fnv.New32a()
|
||||
h.Write([]byte(className))
|
||||
const (
|
||||
baseHz = 1200.0
|
||||
stepHz = 50.0
|
||||
numSteps = uint32(24)
|
||||
)
|
||||
return baseHz + float64(h.Sum32()%numSteps)*stepHz
|
||||
}
|
||||
```
|
||||
|
||||
<!-- From config/config.go — addAutoFreqEntries (lines 225-238) -->
|
||||
```go
|
||||
func addAutoFreqEntries(cfgs map[classify.TrafficClass]synth.FreqConfig, userRules []classify.Rule, autoClasses map[classify.TrafficClass]bool) {
|
||||
for _, rule := range userRules {
|
||||
if _, exists := cfgs[rule.Class]; !exists {
|
||||
baseHz := autoAssignFreq(string(rule.Class))
|
||||
cfgs[rule.Class] = synth.FreqConfig{
|
||||
BaseHz: baseHz,
|
||||
WaveformType: synth.WaveformSine,
|
||||
Harmonics: synth.WaveformPresetHarmonics(synth.WaveformSine, baseHz, synth.SampleRate),
|
||||
Pan: 0.0,
|
||||
}
|
||||
autoClasses[rule.Class] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<!-- From config/config_test.go — current range assertion (line 363) -->
|
||||
```go
|
||||
if cfg.BaseHz < 1200.0 || cfg.BaseHz > 2350.0 {
|
||||
t.Errorf("GameServer BaseHz: got %v, want in [1200, 2350]", cfg.BaseHz)
|
||||
}
|
||||
```
|
||||
</interfaces>
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: Update autoAssignFreq constants and comment</name>
|
||||
<files>config/config.go</files>
|
||||
<read_first>
|
||||
- config/config.go (lines 208-238: autoAssignFreq function and addAutoFreqEntries)
|
||||
</read_first>
|
||||
<action>
|
||||
1. In the `autoAssignFreq` function (line 208-219), update three things:
|
||||
|
||||
a. Change the function comment from `[1200, 2350]` to `[2500, 4000]`:
|
||||
```go
|
||||
// autoAssignFreq computes a deterministic frequency in [2500, 4000] Hz for a class name
|
||||
```
|
||||
|
||||
b. Change the constants inside the function:
|
||||
```go
|
||||
const (
|
||||
baseHz = 2500.0
|
||||
stepHz = 50.0
|
||||
numSteps = uint32(31) // [2500, 4000] Hz in 50 Hz steps
|
||||
)
|
||||
```
|
||||
|
||||
Verification: `2500.0 + float64(30)*50.0 = 4000.0`. With numSteps=31, the modulo produces values 0..30, yielding Hz values 2500, 2550, ..., 4000.
|
||||
|
||||
2. Do NOT modify `addAutoFreqEntries`. The Group field will be zero-value `""` for auto-assigned entries, which is correct — user-defined classes are not part of any built-in family. The struct literal in addAutoFreqEntries does not need a `Group:` field because Go zero-initializes missing named fields.
|
||||
</action>
|
||||
<verify>
|
||||
<automated>cd /home/dev/workspace/yoloyolo && go build ./config/...</automated>
|
||||
</verify>
|
||||
<acceptance_criteria>
|
||||
- config/config.go contains `baseHz = 2500.0` (NOT 1200.0)
|
||||
- config/config.go contains `numSteps = uint32(31)` (NOT 24)
|
||||
- config/config.go contains `// autoAssignFreq computes a deterministic frequency in [2500, 4000] Hz`
|
||||
- config/config.go still contains `stepHz = 50.0` (unchanged)
|
||||
- `go build ./config/...` exits 0
|
||||
</acceptance_criteria>
|
||||
<done>autoAssignFreq produces frequencies in [2500, 4000] Hz range with 31 steps of 50 Hz</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: Update config_test.go auto-assign range assertion</name>
|
||||
<files>config/config_test.go</files>
|
||||
<read_first>
|
||||
- config/config_test.go (search for `1200.0` and `2350.0` — the TestAutoFreqAssignment assertion around line 363)
|
||||
</read_first>
|
||||
<action>
|
||||
1. In `TestAutoFreqAssignment` (around line 363), update the range assertion:
|
||||
|
||||
Change from:
|
||||
```go
|
||||
if cfg.BaseHz < 1200.0 || cfg.BaseHz > 2350.0 {
|
||||
t.Errorf("GameServer BaseHz: got %v, want in [1200, 2350]", cfg.BaseHz)
|
||||
}
|
||||
```
|
||||
|
||||
To:
|
||||
```go
|
||||
if cfg.BaseHz < 2500.0 || cfg.BaseHz > 4000.0 {
|
||||
t.Errorf("GameServer BaseHz: got %v, want in [2500, 4000]", cfg.BaseHz)
|
||||
}
|
||||
```
|
||||
|
||||
2. Also update the test comment at the top of TestAutoFreqAssignment (around line 344-346) from:
|
||||
```
|
||||
// NO [sounds.GameServer] -> FreqCfgs contains "GameServer" entry with BaseHz in [1200, 2350]
|
||||
```
|
||||
To:
|
||||
```
|
||||
// NO [sounds.GameServer] -> FreqCfgs contains "GameServer" entry with BaseHz in [2500, 4000]
|
||||
```
|
||||
|
||||
3. Check if `TestAutoFreqSkipsBuiltins` (around line 563) references `BaseHz == 175.0` for HTTPS. After Plan 01 rebalances HTTPS to 150.0, this test will need its expected value updated from `175.0` to `150.0`. Find the assertion and update it.
|
||||
|
||||
Search for `175.0` in config_test.go and update to `150.0` wherever it references the built-in HTTPS BaseHz.
|
||||
</action>
|
||||
<verify>
|
||||
<automated>cd /home/dev/workspace/yoloyolo && go test ./config/... -v -count=1 -run "TestAutoFreq"</automated>
|
||||
</verify>
|
||||
<acceptance_criteria>
|
||||
- config/config_test.go contains `cfg.BaseHz < 2500.0 || cfg.BaseHz > 4000.0` (NOT 1200/2350)
|
||||
- config/config_test.go contains `want in [2500, 4000]` in the error message
|
||||
- config/config_test.go contains `BaseHz in [2500, 4000]` in the test comment
|
||||
- If HTTPS 175.0 was referenced, it is now 150.0
|
||||
- `go test ./config/... -run TestAutoFreqAssignment` exits 0
|
||||
- `go test ./config/... -run TestAutoFreqDeterministic` exits 0
|
||||
- `go test ./config/... -run TestAutoFreqSkipsBuiltins` exits 0
|
||||
</acceptance_criteria>
|
||||
<done>All auto-assign test assertions match new [2500, 4000] range; HTTPS built-in reference updated to 150.0 if applicable; all config tests pass</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<verification>
|
||||
- `go build ./config/...` compiles without errors
|
||||
- `go test ./config/... -v -run "TestAutoFreq"` passes all auto-freq tests
|
||||
- `go test ./...` passes full suite (cross-package with synth changes from Plan 01)
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- autoAssignFreq base is 2500.0 Hz, not 1200.0 (FREQ-04)
|
||||
- numSteps is 31, producing range [2500, 4000] with 50 Hz steps
|
||||
- No collision possible between built-in frequencies (max 2449 Hz) and auto-assign (min 2500 Hz)
|
||||
- All config tests pass with updated assertions
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
After completion, create `.planning/phases/09-frequency-design-and-group-architecture/09-02-SUMMARY.md`
|
||||
</output>
|
||||
Reference in New Issue
Block a user