225 lines
12 KiB
Markdown
225 lines
12 KiB
Markdown
---
|
|
phase: 11-synthesis-and-config-layer
|
|
plan: 01
|
|
type: execute
|
|
wave: 1
|
|
depends_on: []
|
|
files_modified:
|
|
- synth/config.go
|
|
- classify/types.go
|
|
- synth/bank_test.go
|
|
- config/config_test.go
|
|
- classify/classifier_test.go
|
|
autonomous: true
|
|
requirements:
|
|
- GRP-02
|
|
- GRP-03
|
|
|
|
must_haves:
|
|
truths:
|
|
- "ClassFreqConfigs has exactly 35 entries matching AllClasses()"
|
|
- "Every new class has correct Hz, waveform, pan, and group from frequency allocation table"
|
|
- "LDAP, Kerberos, Syslog appear in AllClasses() and have Infrastructure group with Triangle waveform"
|
|
- "go test ./synth/... ./classify/... ./config/... all pass"
|
|
artifacts:
|
|
- path: "synth/config.go"
|
|
provides: "21 new ClassFreqConfigs entries"
|
|
contains: "classify.ClassIMAP"
|
|
- path: "classify/types.go"
|
|
provides: "AllClasses() returns 35 entries including LDAP/Kerberos/Syslog"
|
|
contains: "ClassLDAP"
|
|
key_links:
|
|
- from: "synth/config.go"
|
|
to: "classify/types.go"
|
|
via: "ClassFreqConfigs references TrafficClass constants"
|
|
pattern: "classify\\.Class(IMAP|POP3|SMTPSub|RDP|Telnet|VNC|FTP|SMB|TFTP|MySQL|PostgreSQL|Redis|MongoDB|SIP|QUIC|MDNS|SSDP|SNMP|LDAP|Kerberos|Syslog)"
|
|
---
|
|
|
|
<objective>
|
|
Add all 21 missing ClassFreqConfigs entries and update AllClasses() to include LDAP/Kerberos/Syslog, then fix every hardcoded count assertion across synth, config, and classify test files.
|
|
|
|
Purpose: This is the foundational data layer for Phase 11 -- all subsequent work (PrintConfig group headers, TOML [groups]) depends on all 35 classes having complete synthesis configs.
|
|
Output: synth/config.go with 35 ClassFreqConfigs entries, classify/types.go with 35-entry AllClasses(), all count-based tests green.
|
|
</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
|
|
@synth/config.go
|
|
@classify/types.go
|
|
@synth/bank_test.go
|
|
@synth/config_test.go
|
|
@config/config_test.go
|
|
@classify/classifier_test.go
|
|
|
|
<interfaces>
|
|
<!-- Key types and contracts the executor needs -->
|
|
|
|
From classify/types.go:
|
|
```go
|
|
type TrafficClass string
|
|
// Constants: ClassIMAP, ClassPOP3, ClassSMTPSub, ClassFTP, ClassSMB, ClassTFTP,
|
|
// ClassRDP, ClassTelnet, ClassVNC, ClassMySQL, ClassPostgreSQL, ClassRedis,
|
|
// ClassMongoDB, ClassMDNS, ClassSSDP, ClassSNMP, ClassSIP, ClassQUIC,
|
|
// ClassLDAP, ClassKerberos, ClassSyslog
|
|
func AllClasses() []TrafficClass
|
|
```
|
|
|
|
From synth/config.go:
|
|
```go
|
|
type FreqConfig struct {
|
|
BaseHz float64
|
|
Harmonics []HarmonicDef
|
|
Pan float64
|
|
WaveformType WaveformType
|
|
Group string
|
|
}
|
|
var ClassFreqConfigs = map[classify.TrafficClass]FreqConfig{...}
|
|
func WaveformPresetHarmonics(wt WaveformType, baseHz float64, sampleRate int) []HarmonicDef
|
|
```
|
|
</interfaces>
|
|
</context>
|
|
|
|
<tasks>
|
|
|
|
<task type="auto">
|
|
<name>Task 1: Add 21 ClassFreqConfigs entries and update AllClasses()</name>
|
|
<files>synth/config.go, classify/types.go</files>
|
|
<read_first>synth/config.go, classify/types.go</read_first>
|
|
<action>
|
|
**synth/config.go** -- Add 21 new entries to the ClassFreqConfigs map, after the existing entries and before the closing brace. Use WaveformPresetHarmonics() for all entries (per D-01). The exact values from the frequency allocation table (lines 74-110 of synth/config.go):
|
|
|
|
```
|
|
// --- Infrastructure additions (Triangle, 93-118 Hz) ---
|
|
classify.ClassMDNS: {BaseHz: 93.0, WaveformType: WaveformTriangle, Harmonics: WaveformPresetHarmonics(WaveformTriangle, 93.0, SampleRate), Pan: 0.3, Group: "Infrastructure"}
|
|
classify.ClassSSDP: {BaseHz: 105.0, WaveformType: WaveformTriangle, Harmonics: WaveformPresetHarmonics(WaveformTriangle, 105.0, SampleRate), Pan: -0.2, Group: "Infrastructure"}
|
|
classify.ClassSNMP: {BaseHz: 118.0, WaveformType: WaveformTriangle, Harmonics: WaveformPresetHarmonics(WaveformTriangle, 118.0, SampleRate), Pan: 0.2, Group: "Infrastructure"}
|
|
// --- Web addition (Sawtooth, 190 Hz) ---
|
|
classify.ClassQUIC: {BaseHz: 190.0, WaveformType: WaveformSawtooth, Harmonics: WaveformPresetHarmonics(WaveformSawtooth, 190.0, SampleRate), Pan: -0.2, Group: "Web"}
|
|
// --- Mail additions (Triangle, 241-305 Hz) ---
|
|
classify.ClassIMAP: {BaseHz: 241.0, WaveformType: WaveformTriangle, Harmonics: WaveformPresetHarmonics(WaveformTriangle, 241.0, SampleRate), Pan: 0.3, Group: "Mail"}
|
|
classify.ClassPOP3: {BaseHz: 271.0, WaveformType: WaveformTriangle, Harmonics: WaveformPresetHarmonics(WaveformTriangle, 271.0, SampleRate), Pan: 0.4, Group: "Mail"}
|
|
classify.ClassSMTPSub: {BaseHz: 305.0, WaveformType: WaveformTriangle, Harmonics: WaveformPresetHarmonics(WaveformTriangle, 305.0, SampleRate), Pan: 0.5, Group: "Mail"}
|
|
// --- Remote Access additions (Square, 385-485 Hz) ---
|
|
classify.ClassRDP: {BaseHz: 385.0, WaveformType: WaveformSquare, Harmonics: WaveformPresetHarmonics(WaveformSquare, 385.0, SampleRate), Pan: -0.6, Group: "Remote Access"}
|
|
classify.ClassTelnet: {BaseHz: 432.0, WaveformType: WaveformSquare, Harmonics: WaveformPresetHarmonics(WaveformSquare, 432.0, SampleRate), Pan: -0.5, Group: "Remote Access"}
|
|
classify.ClassVNC: {BaseHz: 485.0, WaveformType: WaveformSquare, Harmonics: WaveformPresetHarmonics(WaveformSquare, 485.0, SampleRate), Pan: -0.4, Group: "Remote Access"}
|
|
// --- File Transfer additions (Square, 545-687 Hz) ---
|
|
classify.ClassFTP: {BaseHz: 545.0, WaveformType: WaveformSquare, Harmonics: WaveformPresetHarmonics(WaveformSquare, 545.0, SampleRate), Pan: 0.5, Group: "File Transfer"}
|
|
classify.ClassSMB: {BaseHz: 612.0, WaveformType: WaveformSquare, Harmonics: WaveformPresetHarmonics(WaveformSquare, 612.0, SampleRate), Pan: 0.6, Group: "File Transfer"}
|
|
classify.ClassTFTP: {BaseHz: 687.0, WaveformType: WaveformSquare, Harmonics: WaveformPresetHarmonics(WaveformSquare, 687.0, SampleRate), Pan: 0.7, Group: "File Transfer"}
|
|
// --- Database additions (Sawtooth, 1543-2182 Hz) ---
|
|
classify.ClassMySQL: {BaseHz: 1543.0, WaveformType: WaveformSawtooth, Harmonics: WaveformPresetHarmonics(WaveformSawtooth, 1543.0, SampleRate), Pan: -0.4, Group: "Database"}
|
|
classify.ClassPostgreSQL: {BaseHz: 1732.0, WaveformType: WaveformSawtooth, Harmonics: WaveformPresetHarmonics(WaveformSawtooth, 1732.0, SampleRate), Pan: -0.2, Group: "Database"}
|
|
classify.ClassRedis: {BaseHz: 1944.0, WaveformType: WaveformSawtooth, Harmonics: WaveformPresetHarmonics(WaveformSawtooth, 1944.0, SampleRate), Pan: 0.2, Group: "Database"}
|
|
classify.ClassMongoDB: {BaseHz: 2182.0, WaveformType: WaveformSawtooth, Harmonics: WaveformPresetHarmonics(WaveformSawtooth, 2182.0, SampleRate), Pan: 0.4, Group: "Database"}
|
|
// --- VoIP (Sine, 2449 Hz) ---
|
|
classify.ClassSIP: {BaseHz: 2449.0, WaveformType: WaveformSine, Harmonics: WaveformPresetHarmonics(WaveformSine, 2449.0, SampleRate), Pan: 0.0, Group: "VoIP"}
|
|
// --- Infrastructure auto-assigned (Triangle, 2950-3250 Hz) per D-02 ---
|
|
classify.ClassLDAP: {BaseHz: 2950.0, WaveformType: WaveformTriangle, Harmonics: WaveformPresetHarmonics(WaveformTriangle, 2950.0, SampleRate), Pan: -0.2, Group: "Infrastructure"}
|
|
classify.ClassKerberos: {BaseHz: 3250.0, WaveformType: WaveformTriangle, Harmonics: WaveformPresetHarmonics(WaveformTriangle, 3250.0, SampleRate), Pan: 0.0, Group: "Infrastructure"}
|
|
classify.ClassSyslog: {BaseHz: 3050.0, WaveformType: WaveformTriangle, Harmonics: WaveformPresetHarmonics(WaveformTriangle, 3050.0, SampleRate), Pan: 0.2, Group: "Infrastructure"}
|
|
```
|
|
|
|
Place new entries in the map grouped by family with section comments matching the existing pattern (e.g., `// --- Infrastructure additions ...`). Insert them logically:
|
|
- Infrastructure additions (mDNS, SSDP, SNMP) after ClassDHCP and before ClassDNS (since 93/105/118 Hz come between DHCP=82 and DNS=133)
|
|
- Web addition (QUIC) after ClassHTTP
|
|
- Mail additions after ClassSMTP
|
|
- Remote Access additions after ClassSSH
|
|
- File Transfer after Unknown entries
|
|
- Database after Unknown entries
|
|
- VoIP after Database
|
|
- LDAP/Kerberos/Syslog at end (auto-assigned range)
|
|
|
|
**classify/types.go** -- Per D-02 and D-03:
|
|
1. Add ClassLDAP, ClassKerberos, ClassSyslog to AllClasses() in the Infrastructure section, after ClassSNMP.
|
|
2. Remove the comment "Excludes ClassLDAP, ClassKerberos, and ClassSyslog" from the AllClasses() doc comment.
|
|
3. Update the doc comment to say "AllClasses returns all known traffic classes in display order."
|
|
4. The AllClasses() function should now return 35 entries total.
|
|
</action>
|
|
<verify>
|
|
<automated>cd /home/dev/workspace/yoloyolo && go build ./synth/... ./classify/...</automated>
|
|
</verify>
|
|
<acceptance_criteria>
|
|
- `grep -c "classify\.Class" synth/config.go` shows at least 35 occurrences in ClassFreqConfigs
|
|
- `grep "ClassLDAP" classify/types.go` appears in AllClasses() return slice
|
|
- `grep "ClassKerberos" classify/types.go` appears in AllClasses() return slice
|
|
- `grep "ClassSyslog" classify/types.go` appears in AllClasses() return slice
|
|
- `go build ./synth/... ./classify/...` succeeds
|
|
</acceptance_criteria>
|
|
<done>ClassFreqConfigs has 35 entries with correct Hz/waveform/pan/group values. AllClasses() returns 35 entries including LDAP/Kerberos/Syslog. Both packages compile.</done>
|
|
</task>
|
|
|
|
<task type="auto">
|
|
<name>Task 2: Fix all hardcoded count assertions in tests</name>
|
|
<files>synth/bank_test.go, config/config_test.go, classify/classifier_test.go</files>
|
|
<read_first>synth/bank_test.go, config/config_test.go, classify/classifier_test.go</read_first>
|
|
<action>
|
|
Update all hardcoded count assertions to reflect the new 35-entry state. Per research Pitfall 1 and Pitfall 2:
|
|
|
|
**synth/bank_test.go:**
|
|
- Line 10: Rename `TestNewBankHas14Layers` to `TestNewBankHasAllLayers`
|
|
- Line 12: Change `len(b.layers) != 14` to `len(b.layers) != len(classify.AllClasses())`
|
|
- Line 13: Change `want 14` to a dynamic message using `len(classify.AllClasses())`
|
|
|
|
**config/config_test.go:**
|
|
- Line 120: Change `len(cfgs) != 14` to `len(cfgs) != len(classify.AllClasses())` in TestLoadNoConfig
|
|
- Line 149: Change `len(cfgs) != 14` to `len(cfgs) != len(classify.AllClasses())` in TestLoadUnknownClass
|
|
- Line 180: Change `len(cfgs) != 14` to `len(cfgs) != len(classify.AllClasses())` in TestLoadAllDefaultsPresent
|
|
- Line 617: Change `len(result.FreqCfgs) != 14` to `len(result.FreqCfgs) != len(classify.AllClasses())` in TestLoadNoConfigReturnsLoadResult
|
|
- Lines 407-416 in TestPrintConfigContainsAllClasses: Replace the hardcoded `classNames` slice with a loop over `classify.AllClasses()`. Change to:
|
|
```go
|
|
for _, cls := range classify.AllClasses() {
|
|
if !strings.Contains(output, string(cls)) {
|
|
t.Errorf("PrintConfig output missing class %q", cls)
|
|
}
|
|
}
|
|
```
|
|
|
|
**classify/classifier_test.go:**
|
|
- Line 459 (approximately): Change `want 32` to `want 35` in TestAllClassesCount. Update the assertion value from 32 to 35.
|
|
|
|
Use `len(classify.AllClasses())` for dynamic counts wherever possible (synth and config tests). For classifier_test.go, use the literal 35 since the test is specifically verifying the count is a known value per D-03.
|
|
</action>
|
|
<verify>
|
|
<automated>cd /home/dev/workspace/yoloyolo && go test ./synth/... ./classify/... ./config/...</automated>
|
|
</verify>
|
|
<acceptance_criteria>
|
|
- `go test ./synth/...` passes (0 failures)
|
|
- `go test ./classify/...` passes (0 failures)
|
|
- `go test ./config/...` passes (0 failures)
|
|
- `grep "14" synth/bank_test.go` returns no lines with hardcoded layer counts
|
|
- `grep 'want 14' config/config_test.go` returns no matches
|
|
- `grep 'want 32' classify/classifier_test.go` returns no matches
|
|
</acceptance_criteria>
|
|
<done>All test suites pass with 35 classes. No hardcoded counts of 14 or 32 remain in test assertions. TestNewBankHas14Layers renamed to TestNewBankHasAllLayers.</done>
|
|
</task>
|
|
|
|
</tasks>
|
|
|
|
<verification>
|
|
```bash
|
|
cd /home/dev/workspace/yoloyolo && go test ./...
|
|
```
|
|
All tests pass. ClassFreqConfigs has 35 entries matching AllClasses().
|
|
</verification>
|
|
|
|
<success_criteria>
|
|
- `go test ./...` passes fully
|
|
- ClassFreqConfigs map has exactly 35 entries
|
|
- AllClasses() returns exactly 35 entries
|
|
- No hardcoded counts of 14 or 32 remain in test files
|
|
- Every new entry uses WaveformPresetHarmonics() (not hand-tuned harmonics)
|
|
- LDAP/Kerberos/Syslog have Group="Infrastructure" and WaveformTriangle
|
|
</success_criteria>
|
|
|
|
<output>
|
|
After completion, create `.planning/phases/11-synthesis-and-config-layer/11-01-SUMMARY.md`
|
|
</output>
|