docs(11): create phase plan
This commit is contained in:
@@ -0,0 +1,224 @@
|
||||
---
|
||||
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>
|
||||
Reference in New Issue
Block a user