docs(07): capture phase context

This commit is contained in:
2026-03-26 21:27:29 +01:00
parent dddfb1b444
commit fe372c8dc8
2 changed files with 196 additions and 0 deletions
@@ -0,0 +1,123 @@
# Phase 7: Custom Rules and Print-Config - Context
**Gathered:** 2026-03-26
**Status:** Ready for planning
<domain>
## Phase Boundary
Add user-defined traffic classification rules in TOML (`[[rules]]` array-of-tables) that prepend before built-in rules, with automatic synthesis layer creation for new class names. Add `--print-config` flag that outputs the full effective config as commented TOML to stdout without starting a capture.
Requirements covered: RULE-01, RULE-02, RULE-03, CFG-06.
</domain>
<decisions>
## Implementation Decisions
### Custom Rule TOML Schema
- **D-01:** Custom rules use TOML array-of-tables `[[rules]]` with three fields: `port` (uint16, optional — omit to match any port), `protocol` (string, required — "tcp", "udp", or "icmp"), and `class` (string, required — the TrafficClass name). Sound configuration for the class goes in a separate `[sounds.<class>]` block.
- **D-02:** Port is optional. When omitted (or 0), the rule matches all traffic for the given protocol, mirroring the existing `Rule.DstPort = 0` semantics in `classify.DefaultRules`.
- **D-03:** Protocol is required. No implicit "match both TCP and UDP" behavior. User must write separate rules for each protocol.
### Rule Ordering and Priority
- **D-04:** User-defined rules are prepended before built-in `DefaultRules` (RULE-02). First-match-wins semantics are preserved. A user rule for port 443/tcp fires before the built-in HTTPS rule.
- **D-05:** Rules within the TOML `[[rules]]` array maintain their file order. First rule in the file is first to match.
### Class Name Collision Policy
- **D-06:** User-defined class names that match built-in names (e.g., `class = "HTTPS"`) are treated as overrides, not errors. The user's rule fires first (prepended), so traffic matching it gets classified under the same built-in class name via the user rule. Sound config in `[sounds.HTTPS]` still applies. This resolves the design question flagged in STATE.md.
### Sound Assignment for Custom Classes
- **D-07:** New class names that have no `[sounds.<class>]` entry automatically get sensible defaults: a frequency from an unused range and sine waveform. This satisfies RULE-03 (no silent gaps for user-defined classes).
- **D-08:** (Claude's Discretion) The auto-assignment algorithm — how to pick frequencies for new classes that don't collide with built-in frequencies. Could use a hash of the class name, a sequential pool, or a deterministic spread across an unused frequency band.
### Print-Config
- **D-09:** `--print-config` outputs the full effective config (defaults merged with user overrides and custom rules) as commented TOML. Comments indicate which values are defaults vs overrides. This satisfies CFG-06.
- **D-10:** Output goes to stdout (pipeable). User can do `netsynth --print-config > template.toml` to create a config template. The command exits without starting a capture.
- **D-11:** If a config file is loaded (via auto-discovery or `--config`), show its source path in a header comment.
### Config Package Extension
- **D-12:** The existing `config.Load()` function must be extended to parse `[[rules]]` blocks in addition to `[sounds.*]`. The `rawConfig` struct gains a `Rules []RawRule` field.
- **D-13:** `config.Load()` returns both the merged `FreqConfig` map and the user rules (as `[]classify.Rule`). The caller prepends user rules before `classify.DefaultRules`.
### Claude's Discretion
- How to extend `rawConfig` struct and `Load()` return type (tuple, struct, or new function)
- Auto-frequency assignment algorithm for custom classes without explicit sound config
- Whether `--print-config` is a Cobra subcommand or a flag on the root command
- How to format the commented TOML output (manual string building vs TOML encoder + post-processing)
</decisions>
<canonical_refs>
## Canonical References
**Downstream agents MUST read these before planning or implementing.**
### Classification System
- `classify/rules.go``Rule` struct (Protocol, DstPort, Class), `DefaultRules` ordered slice, first-match-wins
- `classify/types.go``TrafficClass` string type, `AllClasses()`, `ClassifiedPacket`, `WindowSnapshot`
- `classify/classifier.go``NewClassifier(rules []Rule)` — accepts injected rule slice
### Config System (Phase 6 output)
- `config/config.go``Load()`, `rawConfig`, `SoundOverride`, `merge()`, `validate()`, `parseWaveform()`
- `config/config_test.go` — Existing test patterns for TOML loading
### Synthesis Pipeline
- `synth/config.go``FreqConfig`, `ClassFreqConfigs`, `WaveformType`, `WaveformPresetHarmonics()`
- `synth/bank.go``NewBank(tau, cfgs map[TrafficClass]FreqConfig)` — injection point for merged config
- `encode/mp3.go``RunSynthesis(snapshots, outputPath, freqCfgs)` — pipeline entry
### CLI
- `cmd/netsynth/main.go` — Cobra command, `--config` flag, `run()` dispatches to live/pcap modes
### Prior Context
- `.planning/phases/06-config-package-and-sound-overrides/06-CONTEXT.md` — Phase 6 decisions (TOML schema, merge semantics, validation)
No external specs — requirements fully captured in decisions above.
</canonical_refs>
<code_context>
## Existing Code Insights
### Reusable Assets
- `classify.Rule` struct — Already has Protocol, DstPort, Class fields matching the TOML schema
- `classify.NewClassifier(rules []Rule)` — Accepts any rule slice, so prepending user rules is straightforward
- `config.Load()` — Existing TOML loading with BurntSushi/toml, validation, and merge pipeline
- `config.rawConfig` — Top-level decode struct, needs `Rules` field added
- `config.parseWaveform()` — Reusable for validating waveform strings in sound overrides
- `synth.NewBank(tau, cfgs)` — Already accepts arbitrary config maps (Phase 5 injection seam)
### Established Patterns
- First-match-wins rule ordering in `classify.DefaultRules`
- TOML strict decoding with `Undecoded()` for unknown key detection
- Pointer fields (`*float64`, `*string`) for partial override semantics
- Config loaded once at startup before capture (fail-fast)
### Integration Points
- `config.Load()` return value must expand to include user rules
- `cmd/netsynth/main.go:run()` — Prepend user rules before passing to `classify.NewClassifier()`
- `config.merge()` — Must handle new class names by creating `FreqConfig` entries with auto-assigned frequencies
- `--print-config` — New flag or subcommand in Cobra root command
</code_context>
<specifics>
## Specific Ideas
- Print-config should show commented TOML with `# default` / `# override` annotations and source path header
- Output to stdout so users can pipe to a file as a template
</specifics>
<deferred>
## Deferred Ideas
None — discussion stayed within phase scope.
</deferred>
---
*Phase: 07-custom-rules-and-print-config*
*Context gathered: 2026-03-26*
@@ -0,0 +1,73 @@
# Phase 7: Custom Rules and Print-Config - 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-26
**Phase:** 07-custom-rules-and-print-config
**Areas discussed:** Custom rule TOML schema, Class name collision policy, Print-config output format, Sound assignment for custom classes
---
## Custom Rule TOML Schema
| Option | Description | Selected |
|--------|-------------|----------|
| Minimal: port + protocol + class | Matches existing Rule struct. Sound config in separate [sounds.X]. | ✓ |
| Inline sound: port + protocol + class + frequency/waveform | All-in-one rule block, mixes classification and sound concerns. | |
| Rich matching: port ranges, src/dst, regex | More expressive but significantly more complex. | |
**User's choice:** Minimal — port + protocol + class
**Notes:** Protocol is required. Port is optional (omit to match any port for the protocol).
---
## Class Name Collision Policy
| Option | Description | Selected |
|--------|-------------|----------|
| Treat as override | User's rule fires first (prepended), same class name. Simplest model. | ✓ |
| Reject with error | Startup error if user rule uses built-in class name. | |
| Namespace: prefix user classes | User classes get "user-" prefix. Adds naming complexity. | |
**User's choice:** Treat as override
**Notes:** Resolves the design question flagged in STATE.md since Phase 5 research.
---
## Print-Config Output Format
| Option | Description | Selected |
|--------|-------------|----------|
| Commented TOML | Valid TOML with comments showing default vs override. Pipeable to file. | ✓ |
| Plain TOML | Clean but doesn't show what's default vs overridden. | |
| Human-readable table | Formatted table, not valid TOML. | |
**User's choice:** Commented TOML to stdout
**Notes:** Output to stdout so `netsynth --print-config > template.toml` works. Shows source path in header comment.
---
## Sound Assignment for Custom Classes
| Option | Description | Selected |
|--------|-------------|----------|
| Auto-assign sensible defaults | Pick unused frequency + sine waveform. No silence. | ✓ |
| Require explicit [sounds.X] | Error if no matching sound config. More friction. | |
| Single fallback tone | All custom classes share one tone. Defeats distinct sounds purpose. | |
**User's choice:** Auto-assign sensible defaults
**Notes:** Satisfies RULE-03 (no silent gaps). Algorithm left to Claude's discretion.
---
## Claude's Discretion
- Auto-frequency assignment algorithm
- --print-config as flag vs subcommand
- Commented TOML formatting approach
- config.Load() return type extension
## Deferred Ideas
None — discussion stayed within phase scope.