chore: archive v1.2 milestone — Extended Protocol Coverage
35 traffic classes across 9 protocol families shipped. Archives ROADMAP, REQUIREMENTS, and phase directories to milestones/v1.2-*. Updates README with new protocol families, sound design table, and [groups] TOML config documentation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -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\\)"
|
||||
---
|
||||
|
||||
<objective>
|
||||
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.
|
||||
</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/08-test-and-constant-cleanup/08-CONTEXT.md
|
||||
@.planning/phases/08-test-and-constant-cleanup/08-RESEARCH.md
|
||||
|
||||
<interfaces>
|
||||
<!-- Key constants and types the executor needs from synth/config.go -->
|
||||
|
||||
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
|
||||
```
|
||||
</interfaces>
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: Delete stale NumLayers and GainPerLayer constants from synth/config.go</name>
|
||||
<files>synth/config.go</files>
|
||||
<read_first>
|
||||
- synth/config.go (see current constant block at lines 5-12)
|
||||
- synth/bank.go (line 21 confirms gainPerLayer is computed dynamically)
|
||||
</read_first>
|
||||
<action>
|
||||
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.
|
||||
</action>
|
||||
<verify>
|
||||
<automated>cd /home/dev/workspace/yoloyolo && grep -n "NumLayers\|GainPerLayer" synth/config.go; echo "EXIT:$?"</automated>
|
||||
</verify>
|
||||
<acceptance_criteria>
|
||||
- `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)
|
||||
</acceptance_criteria>
|
||||
<done>NumLayers and GainPerLayer constants no longer exist in synth/config.go. The constant block contains only SampleRate, WindowMs, SamplesPerWindow, and WhisperFloor. Code compiles cleanly.</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: Update synth/config_test.go — future-proof frequency bounds, rename test, remove duplicate</name>
|
||||
<files>synth/config_test.go</files>
|
||||
<read_first>
|
||||
- synth/config_test.go (full file — see all 6 test functions)
|
||||
- synth/config.go (after Task 1 edits — confirm SampleRate is exported)
|
||||
</read_first>
|
||||
<action>
|
||||
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.
|
||||
</action>
|
||||
<verify>
|
||||
<automated>cd /home/dev/workspace/yoloyolo && go test ./synth/... -v -count=1 2>&1 | head -40</automated>
|
||||
</verify>
|
||||
<acceptance_criteria>
|
||||
- `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)
|
||||
</acceptance_criteria>
|
||||
<done>TestFrequenciesInRange uses Nyquist-based validation (no hardcoded upper bound). TestNumLayersMatchesAllClasses renamed to TestClassFreqConfigsMatchAllClasses. Duplicate TestClassFreqConfigsComplete removed. Full test suite passes.</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<verification>
|
||||
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)
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- 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
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
After completion, create `.planning/phases/08-test-and-constant-cleanup/08-01-SUMMARY.md`
|
||||
</output>
|
||||
@@ -0,0 +1,74 @@
|
||||
---
|
||||
phase: 08-test-and-constant-cleanup
|
||||
plan: 01
|
||||
subsystem: synth
|
||||
tags: [cleanup, constants, tests, ci]
|
||||
dependency_graph:
|
||||
requires: []
|
||||
provides: [clean-constant-block, future-proof-frequency-tests]
|
||||
affects: [synth/config.go, synth/config_test.go]
|
||||
tech_stack:
|
||||
added: []
|
||||
patterns: [Nyquist-based validation instead of hardcoded bounds]
|
||||
key_files:
|
||||
created: []
|
||||
modified:
|
||||
- synth/config.go
|
||||
- synth/config_test.go
|
||||
decisions:
|
||||
- NumLayers and GainPerLayer deleted — NewBank computes gain dynamically as 1/len(cfgs); static constants were dead code after v1.1
|
||||
- TestFrequenciesInRange now validates against Nyquist (22050 Hz) so any BaseHz in (0, 22050) is accepted without test surgery
|
||||
- TestClassFreqConfigsComplete removed as duplicate of TestAllClassesHaveConfig; TestNumLayersMatchesAllClasses renamed to TestClassFreqConfigsMatchAllClasses
|
||||
metrics:
|
||||
duration: "1 min"
|
||||
completed: "2026-03-27"
|
||||
tasks_completed: 2
|
||||
files_modified: 2
|
||||
requirements_satisfied:
|
||||
- CLEAN-01
|
||||
---
|
||||
|
||||
# Phase 8 Plan 1: Constant Cleanup and Future-Proof Tests Summary
|
||||
|
||||
Removed stale exported constants and hardcoded test bounds from the synth package so v1.2 phases can add new traffic classes and frequencies without triggering false CI failures.
|
||||
|
||||
## Tasks Completed
|
||||
|
||||
| Task | Name | Commit | Files |
|
||||
|------|------|--------|-------|
|
||||
| 1 | Delete stale NumLayers and GainPerLayer constants | fd17061 | synth/config.go |
|
||||
| 2 | Update synth/config_test.go — future-proof frequency bounds, rename test, remove duplicate | 4800e8e | synth/config_test.go |
|
||||
|
||||
## What Was Done
|
||||
|
||||
**Task 1** deleted `NumLayers = 14` and `GainPerLayer = 1.0 / float64(NumLayers)` from `synth/config.go`. These constants were dead code since `NewBank` computes `gainPerLayer` dynamically as `1.0 / float64(len(cfgs))`. The constant block now contains only `SampleRate`, `WindowMs`, `SamplesPerWindow`, and `WhisperFloor`.
|
||||
|
||||
**Task 2** made three improvements to `synth/config_test.go`:
|
||||
1. `TestFrequenciesInRange` now validates each `BaseHz` is in `(0, 22050)` using `float64(synth.SampleRate) / 2.0` as the Nyquist bound — no hardcoded upper limit that would reject new protocol classes above 1100 Hz.
|
||||
2. `TestNumLayersMatchesAllClasses` renamed to `TestClassFreqConfigsMatchAllClasses` — name now accurately describes what it tests.
|
||||
3. `TestClassFreqConfigsComplete` deleted — it was a semantic duplicate of `TestAllClassesHaveConfig` (both iterate `AllClasses()` and check for a map entry). Three clean, non-overlapping tests remain.
|
||||
|
||||
## Verification Results
|
||||
|
||||
All six plan verification checks passed:
|
||||
- Zero `NumLayers`/`GainPerLayer` references in `synth/*.go`
|
||||
- Zero hardcoded `1100` bounds in `synth/config_test.go`
|
||||
- `go test ./...` — all 7 packages green
|
||||
- `TestFrequenciesInRange` passes
|
||||
- `TestClassFreqConfigsMatchAllClasses` passes
|
||||
- `TestClassFreqConfigsComplete` no longer exists (correctly)
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
None — plan executed exactly as written.
|
||||
|
||||
## Known Stubs
|
||||
|
||||
None.
|
||||
|
||||
## Self-Check: PASSED
|
||||
|
||||
- synth/config.go exists and contains WhisperFloor, no NumLayers/GainPerLayer
|
||||
- synth/config_test.go exists with nyquist validation, TestClassFreqConfigsMatchAllClasses, no TestClassFreqConfigsComplete
|
||||
- Commits fd17061 and 4800e8e exist
|
||||
- Full test suite green
|
||||
@@ -0,0 +1,88 @@
|
||||
# Phase 8: Test and Constant Cleanup - Context
|
||||
|
||||
**Gathered:** 2026-03-27
|
||||
**Status:** Ready for planning
|
||||
|
||||
<domain>
|
||||
## Phase Boundary
|
||||
|
||||
Remove stale exported constants (`NumLayers`, `GainPerLayer`) from the synth package and update hardcoded test assertions (`TestFrequenciesInRange`) so that subsequent v1.2 phases can add new traffic classes and frequencies without triggering false CI failures. This is pure cleanup — no new features, no new protocols.
|
||||
|
||||
</domain>
|
||||
|
||||
<decisions>
|
||||
## Implementation Decisions
|
||||
|
||||
### Constant Removal Strategy
|
||||
- **D-01:** Delete `NumLayers` and `GainPerLayer` constants entirely from `synth/config.go`. They are dead code — `NewBank` already computes `gainPerLayer` dynamically as `1.0 / float64(len(cfgs))` (bank.go:21). No external callers reference either constant outside the test file.
|
||||
|
||||
### Frequency Range Test Bounds
|
||||
- **D-02:** Replace the hardcoded `[60, 1100]` bounds in `TestFrequenciesInRange` with dynamic validation — derive the valid range from the `ClassFreqConfigs` data itself (e.g., check that all frequencies are positive and below Nyquist) rather than hardcoding a new magic number that would need manual updating when Phase 9/10 add classes above 1100 Hz. The specific approach (positive+Nyquist check, or a generous static bound like `[20, 8000]`) is at Claude's discretion — the key constraint is that adding a new class in the 1100-4000 Hz range must not require editing this test.
|
||||
|
||||
### Test Naming
|
||||
- **D-03:** Rename `TestNumLayersMatchesAllClasses` to `TestClassFreqConfigsMatchAllClasses` (or similar) to reflect the actual invariant being tested after `NumLayers` removal. The test body already uses `len(synth.ClassFreqConfigs)` and `len(classify.AllClasses())` — only the name references the deleted constant.
|
||||
|
||||
### Claude's Discretion
|
||||
- Whether to use a generous static upper bound vs a computed Nyquist-based bound for D-02 — either approach satisfies the constraint
|
||||
- Whether `WhisperFloor` or other constants in config.go need any adjustment (they don't reference NumLayers, so likely no)
|
||||
- Whether `TestClassFreqConfigsComplete` (line 53) should be consolidated with the renamed test since both verify the same invariant
|
||||
|
||||
### Folded Todos
|
||||
- **"Expand Traffic Classes"** (from `.planning/todos/pending/001-expand-traffic-classes.md`) — This todo requests adding protocols like IMAP, POP3, SNMP, FTP and researching common traffic classes. Phase 8 enables this work by removing the test/constant blockers, but the actual protocol additions are Phase 10's scope. Folded here as context, not as direct Phase 8 work.
|
||||
|
||||
</decisions>
|
||||
|
||||
<canonical_refs>
|
||||
## Canonical References
|
||||
|
||||
**Downstream agents MUST read these before planning or implementing.**
|
||||
|
||||
### Synth Package (primary targets)
|
||||
- `synth/config.go` — Contains `NumLayers` and `GainPerLayer` constants to remove (lines 9-10)
|
||||
- `synth/config_test.go` — Contains `TestFrequenciesInRange` (lines 18-24), `TestNumLayersMatchesAllClasses` (lines 61-66), and `TestClassFreqConfigsComplete` (lines 53-59)
|
||||
- `synth/bank.go` — `NewBank` already computes `gainPerLayer` dynamically (line 21) — confirms constants are dead code
|
||||
|
||||
### Research Context
|
||||
- `.planning/research/PITFALLS.md` — Pitfall C4 documents `TestFrequenciesInRange` hardcoding issue
|
||||
- `.planning/research/ARCHITECTURE.md` — Lines 414+ document NumLayers/ClassFreqConfigs mismatch risk
|
||||
- `.planning/research/SUMMARY.md` — Lines 69, 85, 100 describe Phase 8 cleanup scope
|
||||
|
||||
</canonical_refs>
|
||||
|
||||
<code_context>
|
||||
## Existing Code Insights
|
||||
|
||||
### Reusable Assets
|
||||
- `synth/bank.go:NewBank` already has the correct dynamic gain computation — no new code needed for gain behavior
|
||||
|
||||
### Established Patterns
|
||||
- Test file `synth/config_test.go` uses table-driven validation against `ClassFreqConfigs` map and `classify.AllClasses()` — new/renamed tests should follow this pattern
|
||||
- `GainPerLayer` constant at line 10 has a comment referencing "D-10" — cleanup should not leave orphan decision references
|
||||
|
||||
### Integration Points
|
||||
- Only `synth/config.go` and `synth/config_test.go` are modified — no downstream package changes expected
|
||||
- `go test ./...` is the verification gate — must pass with zero new failures
|
||||
|
||||
</code_context>
|
||||
|
||||
<specifics>
|
||||
## Specific Ideas
|
||||
|
||||
No specific requirements — this is a straightforward cleanup phase with clear targets identified in research.
|
||||
|
||||
</specifics>
|
||||
|
||||
<deferred>
|
||||
## Deferred Ideas
|
||||
|
||||
### Reviewed Todos (not folded)
|
||||
None — the matched todo was folded as milestone context.
|
||||
|
||||
None — discussion stayed within phase scope.
|
||||
|
||||
</deferred>
|
||||
|
||||
---
|
||||
|
||||
*Phase: 08-test-and-constant-cleanup*
|
||||
*Context gathered: 2026-03-27*
|
||||
@@ -0,0 +1,60 @@
|
||||
# Phase 8: Test and Constant Cleanup - Discussion Log
|
||||
|
||||
> **Audit trail only.** Do not use as input to planning, research, or execution agents.
|
||||
> Decisions are captured in CONTEXT.md — this log preserves the alternatives considered.
|
||||
|
||||
**Date:** 2026-03-27
|
||||
**Phase:** 08-test-and-constant-cleanup
|
||||
**Areas discussed:** Constant removal strategy, Frequency range bound, Test naming
|
||||
**Mode:** Auto (all decisions auto-selected)
|
||||
|
||||
---
|
||||
|
||||
## Constant Removal Strategy
|
||||
|
||||
| Option | Description | Selected |
|
||||
|--------|-------------|----------|
|
||||
| Delete entirely | Remove NumLayers and GainPerLayer from config.go — bank.go already computes dynamically | ✓ |
|
||||
| Deprecate with comment | Keep but mark as deprecated for backward compatibility | |
|
||||
| Replace with function | Convert to a function that returns len(ClassFreqConfigs) | |
|
||||
|
||||
**User's choice:** [auto] Delete entirely (recommended default)
|
||||
**Notes:** NewBank already computes gainPerLayer as 1.0/len(cfgs). No external callers reference either constant.
|
||||
|
||||
---
|
||||
|
||||
## Frequency Range Test Bound
|
||||
|
||||
| Option | Description | Selected |
|
||||
|--------|-------------|----------|
|
||||
| Dynamic validation | Derive valid range from data (positive + below Nyquist) — no magic numbers | ✓ |
|
||||
| Generous static bound | Replace 1100 with e.g. 8000 Hz — simple but still hardcoded | |
|
||||
| Remove range test | Delete TestFrequenciesInRange entirely — other tests cover correctness | |
|
||||
|
||||
**User's choice:** [auto] Dynamic validation (recommended default)
|
||||
**Notes:** Key constraint: adding a class in 1100-4000 Hz range must not require editing this test.
|
||||
|
||||
---
|
||||
|
||||
## Test Naming
|
||||
|
||||
| Option | Description | Selected |
|
||||
|--------|-------------|----------|
|
||||
| Rename to TestClassFreqConfigsMatchAllClasses | Reflects actual invariant after NumLayers removal | ✓ |
|
||||
| Keep current name | Leave as-is despite referencing deleted constant | |
|
||||
| Delete test | TestClassFreqConfigsComplete already covers same invariant | |
|
||||
|
||||
**User's choice:** [auto] Rename to TestClassFreqConfigsMatchAllClasses (recommended default)
|
||||
**Notes:** Test body already uses len() comparisons, only the name references NumLayers.
|
||||
|
||||
---
|
||||
|
||||
## Claude's Discretion
|
||||
|
||||
- Specific approach for dynamic frequency range validation (Nyquist-based vs generous static bound)
|
||||
- Whether to consolidate TestClassFreqConfigsComplete with renamed test
|
||||
- Whether WhisperFloor needs adjustment (likely not)
|
||||
|
||||
## Deferred Ideas
|
||||
|
||||
None — discussion stayed within phase scope.
|
||||
@@ -0,0 +1,338 @@
|
||||
# Phase 8: Test and Constant Cleanup - Research
|
||||
|
||||
**Researched:** 2026-03-27
|
||||
**Domain:** Go test cleanup, dead code removal, test assertion generalization
|
||||
**Confidence:** HIGH
|
||||
|
||||
<user_constraints>
|
||||
## User Constraints (from CONTEXT.md)
|
||||
|
||||
### Locked Decisions
|
||||
|
||||
- **D-01:** Delete `NumLayers` and `GainPerLayer` constants entirely from `synth/config.go`. They are dead code — `NewBank` already computes `gainPerLayer` dynamically as `1.0 / float64(len(cfgs))` (bank.go:21). No external callers reference either constant outside the test file.
|
||||
- **D-02:** Replace the hardcoded `[60, 1100]` bounds in `TestFrequenciesInRange` with dynamic validation — derive the valid range from the `ClassFreqConfigs` data itself (e.g., check that all frequencies are positive and below Nyquist) rather than hardcoding a new magic number that would need manual updating when Phase 9/10 add classes above 1100 Hz.
|
||||
- **D-03:** Rename `TestNumLayersMatchesAllClasses` to `TestClassFreqConfigsMatchAllClasses` (or similar) to reflect the actual invariant being tested after `NumLayers` removal.
|
||||
|
||||
### Claude's Discretion
|
||||
|
||||
- Whether to use a generous static upper bound vs a computed Nyquist-based bound for D-02 — either approach satisfies the constraint
|
||||
- Whether `WhisperFloor` or other constants in config.go need any adjustment (they don't reference NumLayers, so likely no)
|
||||
- Whether `TestClassFreqConfigsComplete` (line 53) should be consolidated with the renamed test since both verify the same invariant
|
||||
|
||||
### Deferred Ideas (OUT OF SCOPE)
|
||||
|
||||
- Adding protocols (IMAP, POP3, SNMP, FTP, etc.) — this is Phase 10 scope; Phase 8 only removes blockers
|
||||
</user_constraints>
|
||||
|
||||
<phase_requirements>
|
||||
## Phase Requirements
|
||||
|
||||
| ID | Description | Research Support |
|
||||
|----|-------------|------------------|
|
||||
| CLEAN-01 | Remove stale `NumLayers` constant and hardcoded frequency range test assertions that would block new class additions | D-01 removes the constants; D-02 replaces hardcoded bounds with future-proof validation; D-03 renames stale test function |
|
||||
</phase_requirements>
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
Phase 8 is a pure cleanup phase with two narrowly scoped targets: (1) two dead exported constants in `synth/config.go` and (2) three test functions in `synth/config_test.go` that need renaming or rewiring. No new features, no new packages, no new dependencies.
|
||||
|
||||
`NumLayers = 14` and `GainPerLayer = 1.0 / float64(NumLayers)` in `synth/config.go` are provably dead code. `synth/bank.go:NewBank` computes `gainPerLayer` dynamically at line 21 as `1.0 / float64(len(cfgs))`. Neither constant is referenced anywhere in the production code path — only in the test file's function name `TestNumLayersMatchesAllClasses` (which itself does not use either constant in its body). Deleting both constants removes a misleading signal and eliminates the risk of future callers accidentally hardcoding the stale count 14.
|
||||
|
||||
`TestFrequenciesInRange` asserts `cfg.BaseHz < 60 || cfg.BaseHz > 1100`. Phase 9 will redistribute frequencies and Phase 10 will add classes whose frequencies will exceed 1100 Hz. The test will produce false failures the moment any `ClassFreqConfigs` entry above 1100 Hz is added. Replacing the hardcoded upper bound with a Nyquist-based check (or a generous static bound like 8000 Hz) makes the test structurally future-proof without encoding new domain knowledge in this phase.
|
||||
|
||||
**Primary recommendation:** Three surgical edits to two files — delete 2 lines in `config.go`, update 1 test function body + rename 2 test functions in `config_test.go`. Total change surface is under 15 lines.
|
||||
|
||||
---
|
||||
|
||||
## Standard Stack
|
||||
|
||||
No new dependencies. This phase touches only existing Go source files.
|
||||
|
||||
### Core
|
||||
| Library | Version | Purpose | Why Standard |
|
||||
|---------|---------|---------|--------------|
|
||||
| `testing` | stdlib | Test assertions | Already used throughout the codebase |
|
||||
|
||||
**Installation:** None required — no new packages.
|
||||
|
||||
---
|
||||
|
||||
## Architecture Patterns
|
||||
|
||||
### Files Modified (exhaustive list)
|
||||
|
||||
```
|
||||
synth/
|
||||
├── config.go # Delete NumLayers and GainPerLayer constants (lines 9-10)
|
||||
└── config_test.go # Update TestFrequenciesInRange body; rename two test functions
|
||||
```
|
||||
|
||||
No other files are modified. The CONTEXT.md explicitly states: "Only `synth/config.go` and `synth/config_test.go` are modified — no downstream package changes expected."
|
||||
|
||||
### Pattern 1: Dead Constant Removal
|
||||
|
||||
**What:** Delete lines 9-10 from `synth/config.go`.
|
||||
|
||||
**Current state:**
|
||||
```go
|
||||
// synth/config.go lines 5-12
|
||||
const (
|
||||
SampleRate = 44100
|
||||
WindowMs = 500
|
||||
SamplesPerWindow = SampleRate * WindowMs / 1000 // 22050
|
||||
NumLayers = 14
|
||||
GainPerLayer = 1.0 / float64(NumLayers) // D-10: ~0.0714
|
||||
WhisperFloor = 0.03
|
||||
)
|
||||
```
|
||||
|
||||
**After deletion:**
|
||||
```go
|
||||
const (
|
||||
SampleRate = 44100
|
||||
WindowMs = 500
|
||||
SamplesPerWindow = SampleRate * WindowMs / 1000 // 22050
|
||||
WhisperFloor = 0.03
|
||||
)
|
||||
```
|
||||
|
||||
**Verification:** `grep -r "NumLayers\|GainPerLayer" .` must return zero hits in `*.go` files after deletion. The only non-test reference is in `.planning/research/ARCHITECTURE.md` (planning docs — not compiled).
|
||||
|
||||
### Pattern 2: Nyquist-Based Frequency Range Validation
|
||||
|
||||
**What:** Replace the hardcoded `[60, 1100]` upper bound in `TestFrequenciesInRange`.
|
||||
|
||||
**Recommended approach (Nyquist-based):** Phase 9 will add classes up to ~4000 Hz. Nyquist at 44100 Hz sample rate is 22050 Hz. A Nyquist check is mathematically correct and never needs updating regardless of how many new classes are added:
|
||||
|
||||
```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)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Alternative approach (generous static bound):** A bound of `[20, 8000]` also satisfies D-02's constraint since all planned Phase 9/10 frequencies are under 4000 Hz. However the Nyquist approach is self-documenting — it explains *why* there's an upper bound rather than encoding an arbitrary number. Either is acceptable per Claude's Discretion.
|
||||
|
||||
**Key invariant preserved:** Both approaches ensure adding a new class at any humanly-audible frequency (20 Hz – 20 kHz, well within Nyquist) will NOT require editing this test.
|
||||
|
||||
### Pattern 3: Test Function Rename
|
||||
|
||||
**What:** Rename `TestNumLayersMatchesAllClasses` at line 61. The test body already tests the correct invariant (`len(synth.ClassFreqConfigs) == len(classify.AllClasses())`); only the name is stale.
|
||||
|
||||
**Current:**
|
||||
```go
|
||||
func TestNumLayersMatchesAllClasses(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()))
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**After rename:**
|
||||
```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()))
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Pattern 4: Consolidation Decision (Claude's Discretion)
|
||||
|
||||
`TestAllClassesHaveConfig` (lines 10-16) and `TestClassFreqConfigsComplete` (lines 53-59) test the same invariant: every class in `AllClasses()` has an entry in `ClassFreqConfigs`. They are exact duplicates in semantics (different error messages but identical logic). The renamed `TestClassFreqConfigsMatchAllClasses` (formerly `TestNumLayersMatchesAllClasses`) tests the converse: lengths match.
|
||||
|
||||
**Recommendation:** Remove `TestClassFreqConfigsComplete` (lines 53-59) as a duplicate of `TestAllClassesHaveConfig`. This leaves three non-overlapping coverage tests:
|
||||
- `TestAllClassesHaveConfig` — every AllClasses() member has a map entry
|
||||
- `TestClassFreqConfigsMatchAllClasses` — count parity (catches extra entries not in AllClasses)
|
||||
- `TestFrequenciesInRange` — all BaseHz values are positive and below Nyquist
|
||||
|
||||
Alternatively, leave both functions if deduplication is not worth the discussion. Both pass and both protect the invariant. This is truly Claude's discretion.
|
||||
|
||||
### Anti-Patterns to Avoid
|
||||
|
||||
- **Updating `NumLayers` instead of deleting it:** The decision (D-01) is deletion, not update. An updated constant would still be a maintenance burden.
|
||||
- **Replacing [60, 1100] with [60, 4000]:** A new hardcoded number has the same fragility as the old one — it becomes stale when the frequency spectrum changes again in a future milestone.
|
||||
- **Touching `bank.go`:** The dynamic `gainPerLayer` computation in `bank.go` is already correct. No changes needed.
|
||||
- **Touching `classify/types.go`:** `AllClasses()` is not modified in this phase.
|
||||
- **Touching `WhisperFloor`:** It does not reference `NumLayers` or `GainPerLayer`; leave it unchanged.
|
||||
|
||||
---
|
||||
|
||||
## Don't Hand-Roll
|
||||
|
||||
Not applicable. This phase contains no algorithmic code — it is deletion and test rewriting.
|
||||
|
||||
---
|
||||
|
||||
## Common Pitfalls
|
||||
|
||||
### Pitfall 1: Leaving the `GainPerLayer` comment reference orphaned
|
||||
|
||||
**What goes wrong:** `GainPerLayer` at config.go line 10 has a comment `// D-10: ~0.0714`. After deletion, the decision reference D-10 disappears from the source. This is fine — D-10 is still documented in the planning research files. But if the comment is moved to `bank.go` line 21 (where the dynamic computation lives), it improves traceability without leaving an orphan.
|
||||
|
||||
**How to avoid:** Either delete both lines cleanly with no compensation, or add `// D-10: gain is 1/N computed dynamically` to `bank.go:21`. Both are acceptable.
|
||||
|
||||
**Warning signs:** Go compiler catches unused constants — if `NumLayers` or `GainPerLayer` are deleted and the code still compiles, they were indeed dead.
|
||||
|
||||
### Pitfall 2: Using `synth.SampleRate` in the test without verifying the export
|
||||
|
||||
**What goes wrong:** `SampleRate` is an exported constant in `synth/config.go`. The test file is in package `synth_test` (external test package), so it accesses `synth.SampleRate`. Verify `SampleRate` is exported (capital S) before referencing it from the test.
|
||||
|
||||
**How to avoid:** Already confirmed — `SampleRate = 44100` is exported at config.go line 6. No issue.
|
||||
|
||||
**Warning signs:** Compiler error `synth.sampleRate undefined` would indicate a lowercase constant.
|
||||
|
||||
### Pitfall 3: Test duplication confusion
|
||||
|
||||
**What goes wrong:** `TestAllClassesHaveConfig` and `TestClassFreqConfigsComplete` look different but test the same invariant. During code review or future debugging, someone might wonder why there are two tests for the same thing.
|
||||
|
||||
**How to avoid:** If consolidating (removing `TestClassFreqConfigsComplete`), add a comment to `TestAllClassesHaveConfig` noting it replaced the duplicate. If not consolidating, no action needed.
|
||||
|
||||
---
|
||||
|
||||
## Code Examples
|
||||
|
||||
### Resulting `synth/config.go` constant block
|
||||
|
||||
```go
|
||||
// Source: synth/config.go — after Phase 8 cleanup
|
||||
const (
|
||||
SampleRate = 44100
|
||||
WindowMs = 500
|
||||
SamplesPerWindow = SampleRate * WindowMs / 1000 // 22050
|
||||
WhisperFloor = 0.03 // D-08/D-09: 3% of max amplitude
|
||||
)
|
||||
```
|
||||
|
||||
### Resulting `TestFrequenciesInRange` (Nyquist approach)
|
||||
|
||||
```go
|
||||
// Source: synth/config_test.go — after Phase 8 cleanup
|
||||
func TestFrequenciesInRange(t *testing.T) {
|
||||
const nyquist = float64(synth.SampleRate) / 2.0
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Resulting `TestClassFreqConfigsMatchAllClasses`
|
||||
|
||||
```go
|
||||
// Source: synth/config_test.go — after rename from TestNumLayersMatchesAllClasses
|
||||
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()))
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## State of the Art
|
||||
|
||||
| Old Approach | Current Approach | When Changed | Impact |
|
||||
|--------------|------------------|--------------|--------|
|
||||
| `NumLayers = 14` static constant | Dynamic `1.0 / float64(len(cfgs))` in `NewBank` | Phase 6/7 (v1.1) | Static constant is now dead code; remove it |
|
||||
| `TestFrequenciesInRange` checks `[60, 1100]` | Nyquist-based check (this phase) | Phase 8 (v1.2) | Test survives any future frequency allocation |
|
||||
|
||||
---
|
||||
|
||||
## Validation Architecture
|
||||
|
||||
### Test Framework
|
||||
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| Framework | `testing` stdlib, Go 1.24 |
|
||||
| Config file | none (standard `go test`) |
|
||||
| Quick run command | `go test ./synth/...` |
|
||||
| Full suite command | `go test ./...` |
|
||||
|
||||
### Phase Requirements → Test Map
|
||||
|
||||
| Req ID | Behavior | Test Type | Automated Command | File Exists? |
|
||||
|--------|----------|-----------|-------------------|-------------|
|
||||
| CLEAN-01 (constant removal) | `NumLayers` and `GainPerLayer` are not exported from `synth` package | unit — compile check | `go build ./synth/...` | ✅ (config.go exists; delete lines) |
|
||||
| CLEAN-01 (no broken references) | Full test suite passes after deletion | integration | `go test ./...` | ✅ |
|
||||
| CLEAN-01 (range test future-proof) | `TestFrequenciesInRange` passes with any BaseHz in (0, Nyquist) range | unit | `go test ./synth/... -run TestFrequenciesInRange` | ✅ (config_test.go exists; update body) |
|
||||
| CLEAN-01 (test rename) | `TestClassFreqConfigsMatchAllClasses` exists and passes | unit | `go test ./synth/... -run TestClassFreqConfigsMatchAllClasses` | ✅ (rename existing function) |
|
||||
|
||||
### Sampling Rate
|
||||
|
||||
- **Per task commit:** `go test ./synth/...`
|
||||
- **Per wave merge:** `go test ./...`
|
||||
- **Phase gate:** `go test ./...` green before `/gsd:verify-work`
|
||||
|
||||
### Wave 0 Gaps
|
||||
|
||||
None — existing test infrastructure covers all phase requirements. No new test files, fixtures, or framework setup needed.
|
||||
|
||||
---
|
||||
|
||||
## Environment Availability
|
||||
|
||||
Step 2.6: SKIPPED (no external dependencies — pure Go source edits, no new tools or services required).
|
||||
|
||||
Current test suite state confirmed: `go test ./...` passes on all 7 packages.
|
||||
|
||||
---
|
||||
|
||||
## Open Questions
|
||||
|
||||
1. **Consolidate `TestAllClassesHaveConfig` and `TestClassFreqConfigsComplete`?**
|
||||
- What we know: They test the same invariant; both currently pass; no correctness issue either way
|
||||
- What's unclear: Whether the planner wants one clean authoritative test or is fine leaving both
|
||||
- Recommendation: Remove `TestClassFreqConfigsComplete` (lines 53-59) as it duplicates `TestAllClassesHaveConfig`. The named `TestAllClassesHaveConfig` is more expressive. If this causes any concern, leave both — both are correct.
|
||||
|
||||
2. **Add D-10 comment to `bank.go` after deleting `GainPerLayer`?**
|
||||
- What we know: `GainPerLayer` carries `// D-10: ~0.0714`; bank.go line 21 is where the actual computation lives
|
||||
- What's unclear: Whether the project wants decision-reference comments preserved at the implementation site
|
||||
- Recommendation: Add `// D-10: gainPerLayer = 1/N so all N layers at full amplitude sum to 1.0` to bank.go line 21. Low-cost, improves traceability.
|
||||
|
||||
---
|
||||
|
||||
## Sources
|
||||
|
||||
### Primary (HIGH confidence)
|
||||
|
||||
- `synth/config.go` — Direct inspection: `NumLayers = 14`, `GainPerLayer = 1.0 / float64(NumLayers)` at lines 9-10; `SampleRate = 44100` at line 6
|
||||
- `synth/bank.go` — Direct inspection: `gainPerLayer: 1.0 / float64(len(cfgs))` at line 21 — confirms constants are dead code
|
||||
- `synth/config_test.go` — Direct inspection: `TestFrequenciesInRange` body at lines 18-25; `TestNumLayersMatchesAllClasses` at lines 61-66; `TestClassFreqConfigsComplete` at lines 53-59
|
||||
- `classify/types.go` — Direct inspection: `AllClasses()` returns 14 entries; `SampleRate = 44100` used for Nyquist calculation
|
||||
- `.planning/phases/08-test-and-constant-cleanup/08-CONTEXT.md` — Locked decisions D-01, D-02, D-03
|
||||
- `.planning/research/PITFALLS.md` — Pitfall C3 (NumLayers stale constant) and C4 (TestFrequenciesInRange hardcoding)
|
||||
- `.planning/research/ARCHITECTURE.md` lines 414-422 — NumLayers/GainPerLayer dead code analysis
|
||||
|
||||
### Secondary (MEDIUM confidence)
|
||||
|
||||
- `go test ./...` output — All 7 packages pass; current baseline confirmed
|
||||
|
||||
---
|
||||
|
||||
## Metadata
|
||||
|
||||
**Confidence breakdown:**
|
||||
- Standard stack: HIGH — no new dependencies; pure stdlib
|
||||
- Architecture: HIGH — all target lines verified by direct file inspection
|
||||
- Pitfalls: HIGH — sourced from project research files and direct code inspection
|
||||
|
||||
**Research date:** 2026-03-27
|
||||
**Valid until:** Until Phase 9 begins (frequency redistribution) — this research is tied to current `synth/config.go` line numbers which Phase 9 will change
|
||||
@@ -0,0 +1,71 @@
|
||||
---
|
||||
phase: 8
|
||||
slug: test-and-constant-cleanup
|
||||
status: draft
|
||||
nyquist_compliant: false
|
||||
wave_0_complete: false
|
||||
created: 2026-03-27
|
||||
---
|
||||
|
||||
# Phase 8 — Validation Strategy
|
||||
|
||||
> Per-phase validation contract for feedback sampling during execution.
|
||||
|
||||
---
|
||||
|
||||
## Test Infrastructure
|
||||
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| **Framework** | go test (stdlib) |
|
||||
| **Config file** | none — built-in Go test runner |
|
||||
| **Quick run command** | `go test ./synth/...` |
|
||||
| **Full suite command** | `go test ./...` |
|
||||
| **Estimated runtime** | ~5 seconds |
|
||||
|
||||
---
|
||||
|
||||
## Sampling Rate
|
||||
|
||||
- **After every task commit:** Run `go test ./synth/...`
|
||||
- **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 | File Exists | Status |
|
||||
|---------|------|------|-------------|-----------|-------------------|-------------|--------|
|
||||
| 08-01-01 | 01 | 1 | CLEAN-01 | unit | `go test ./synth/... -run TestFrequenciesInRange` | ✅ | ⬜ pending |
|
||||
| 08-01-02 | 01 | 1 | CLEAN-01 | compile | `go build ./synth/...` | ✅ | ⬜ pending |
|
||||
| 08-01-03 | 01 | 1 | CLEAN-01 | unit | `go test ./synth/... -run TestClassFreqConfigs` | ✅ | ⬜ pending |
|
||||
| 08-01-04 | 01 | 1 | CLEAN-01 | integration | `go test ./...` | ✅ | ⬜ pending |
|
||||
|
||||
*Status: ⬜ pending · ✅ green · ❌ red · ⚠️ flaky*
|
||||
|
||||
---
|
||||
|
||||
## Wave 0 Requirements
|
||||
|
||||
*Existing infrastructure covers all phase requirements.*
|
||||
|
||||
---
|
||||
|
||||
## Manual-Only Verifications
|
||||
|
||||
*All phase behaviors have automated verification.*
|
||||
|
||||
---
|
||||
|
||||
## Validation Sign-Off
|
||||
|
||||
- [ ] All tasks have `<automated>` verify or Wave 0 dependencies
|
||||
- [ ] Sampling continuity: no 3 consecutive tasks without automated verify
|
||||
- [ ] Wave 0 covers all MISSING references
|
||||
- [ ] No watch-mode flags
|
||||
- [ ] Feedback latency < 5s
|
||||
- [ ] `nyquist_compliant: true` set in frontmatter
|
||||
|
||||
**Approval:** pending
|
||||
@@ -0,0 +1,91 @@
|
||||
---
|
||||
phase: 08-test-and-constant-cleanup
|
||||
verified: 2026-03-27T10:00:00Z
|
||||
status: passed
|
||||
score: 4/4 must-haves verified
|
||||
re_verification: false
|
||||
---
|
||||
|
||||
# Phase 8: Test and Constant Cleanup Verification Report
|
||||
|
||||
**Phase Goal:** Pre-existing test assertions and a stale exported constant that would block or mislead all subsequent v1.2 work are removed
|
||||
**Verified:** 2026-03-27
|
||||
**Status:** passed
|
||||
**Re-verification:** No — initial verification
|
||||
|
||||
## Goal Achievement
|
||||
|
||||
### Observable Truths
|
||||
|
||||
| # | Truth | Status | Evidence |
|
||||
|---|-------|--------|----------|
|
||||
| 1 | NumLayers and GainPerLayer constants do not exist in the synth package | VERIFIED | `grep -n "NumLayers\|GainPerLayer" synth/config.go synth/bank.go synth/config_test.go` returns zero matches (exit 1 = no matches) |
|
||||
| 2 | `go test ./...` passes with zero failures after all edits | VERIFIED | All 7 packages green: aggregate, capture, classify, cmd/netsynth, config, encode, synth |
|
||||
| 3 | TestFrequenciesInRange accepts any BaseHz in (0, Nyquist) without manual test surgery | VERIFIED | `const nyquist = float64(synth.SampleRate) / 2.0` at line 19; hardcoded `1100` bound absent (grep returns exit 1); test passes |
|
||||
| 4 | TestNumLayersMatchesAllClasses is renamed to TestClassFreqConfigsMatchAllClasses | VERIFIED | `TestClassFreqConfigsMatchAllClasses` present at line 56; `TestNumLayersMatchesAllClasses` absent; `TestClassFreqConfigsComplete` absent |
|
||||
|
||||
**Score:** 4/4 truths verified
|
||||
|
||||
### Required Artifacts
|
||||
|
||||
| Artifact | Expected | Status | Details |
|
||||
|----------|----------|--------|---------|
|
||||
| `synth/config.go` | Cleaned constant block without NumLayers or GainPerLayer; contains WhisperFloor | VERIFIED | Constant block contains SampleRate, WindowMs, SamplesPerWindow, WhisperFloor only (lines 5-10). NumLayers and GainPerLayer absent. |
|
||||
| `synth/config_test.go` | Future-proof test assertions; contains TestClassFreqConfigsMatchAllClasses | VERIFIED | Nyquist-based validation in TestFrequenciesInRange (line 19). TestClassFreqConfigsMatchAllClasses present (line 56). TestClassFreqConfigsComplete absent. |
|
||||
|
||||
### Key Link Verification
|
||||
|
||||
| From | To | Via | Status | Details |
|
||||
|------|----|-----|--------|---------|
|
||||
| `synth/bank.go` | `synth/config.go` | gainPerLayer computed dynamically in NewBank — no static constant conflicts | VERIFIED | `gainPerLayer: 1.0 / float64(len(cfgs))` at line 21 of bank.go; no reference to the deleted NumLayers constant anywhere in synth package |
|
||||
| `synth/config_test.go` | `synth/config.go` | TestFrequenciesInRange validates BaseHz against SampleRate-derived Nyquist | VERIFIED | `float64(synth.SampleRate) / 2.0` at line 19 of config_test.go; test runs and passes |
|
||||
|
||||
### Data-Flow Trace (Level 4)
|
||||
|
||||
Not applicable. This phase modifies a constants file and test file only — no dynamic data rendering involved.
|
||||
|
||||
### Behavioral Spot-Checks
|
||||
|
||||
| Behavior | Command | Result | Status |
|
||||
|----------|---------|--------|--------|
|
||||
| TestFrequenciesInRange passes | `go test ./synth/... -run TestFrequenciesInRange -count=1` | PASS | VERIFIED |
|
||||
| TestClassFreqConfigsMatchAllClasses passes | `go test ./synth/... -run TestClassFreqConfigsMatchAllClasses -count=1` | PASS | VERIFIED |
|
||||
| Full suite green | `go test ./...` | All 7 packages ok | VERIFIED |
|
||||
| Both task commits exist | `git show --stat fd17061 4800e8e` | Both commits present with correct file changes | VERIFIED |
|
||||
|
||||
### Requirements Coverage
|
||||
|
||||
| Requirement | Source Plan | Description | Status | Evidence |
|
||||
|-------------|------------|-------------|--------|----------|
|
||||
| CLEAN-01 | 08-01-PLAN.md | Remove stale NumLayers constant and hardcoded frequency range test assertions that would block new class additions | SATISFIED | NumLayers and GainPerLayer deleted from synth/config.go (commit fd17061); hardcoded 1100 Hz bound replaced with Nyquist-based validation in config_test.go (commit 4800e8e) |
|
||||
|
||||
**Orphaned requirements check:** REQUIREMENTS.md maps only CLEAN-01 to Phase 8. The plan declares CLEAN-01. No orphaned requirements.
|
||||
|
||||
### Anti-Patterns Found
|
||||
|
||||
| File | Line | Pattern | Severity | Impact |
|
||||
|------|------|---------|----------|--------|
|
||||
| — | — | None found | — | — |
|
||||
|
||||
No TODOs, FIXMEs, placeholders, empty returns, or stub indicators in the modified files.
|
||||
|
||||
### Human Verification Required
|
||||
|
||||
None. All phase deliverables are code-verifiable (constant deletion and test assertions checked programmatically).
|
||||
|
||||
### Gaps Summary
|
||||
|
||||
No gaps. All four must-have truths are verified against the actual codebase:
|
||||
|
||||
- `synth/config.go` constant block contains exactly SampleRate, WindowMs, SamplesPerWindow, and WhisperFloor — the two stale constants are gone.
|
||||
- `synth/config_test.go` uses Nyquist-derived bounds (22050 Hz) with no hardcoded 1100 Hz upper limit — adding a new class at any frequency up to 22050 Hz requires no test edits.
|
||||
- The old `TestNumLayersMatchesAllClasses` name is gone; `TestClassFreqConfigsMatchAllClasses` replaced it with identical body.
|
||||
- The duplicate `TestClassFreqConfigsComplete` is removed.
|
||||
- All 7 packages pass `go test ./...` with zero failures.
|
||||
|
||||
The phase goal is fully achieved: no stale constants or hardcoded test bounds remain to block v1.2 work.
|
||||
|
||||
---
|
||||
|
||||
_Verified: 2026-03-27_
|
||||
_Verifier: Claude (gsd-verifier)_
|
||||
Reference in New Issue
Block a user