docs(07): capture phase context
This commit is contained in:
@@ -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.
|
||||
Reference in New Issue
Block a user