# flowscope 0.8 — Plan of record
**Date:** 2026-06-06
**Source:** [`docs/feedback-2026-06-06-netring-wishlist.md`](./feedback-2026-06-06-netring-wishlist.md)
— consolidated netring wishlist (top of 3 prior feedback rounds; round 1
drove 0.5/0.6, round 2 drove 0.7).
**Backward compatibility:** breaking changes are *in scope*. Pre-1.0
policy ([`plans/INDEX.md`](../plans/INDEX.md)) allows it; `netring`
updates in lockstep and `CHANGELOG.md` carries migration recipes.
---
## 1. Verdict
The wishlist crystallises three feedback rounds into a focused 0.8 ask:
the L7 surface is stable enough that a serde lock-in is now appropriate
(A1), the ICMP module needs the helper accessors the original ship plan
deliberately left out (A2), and the cross-protocol correlation pattern
needs its first concrete primitive shipped in-crate (A3). Plus six
smaller items where the pattern is clear.
We adopt eight of the eleven proposed items for 0.8.0 (everything in
Sections A + B except B2's full driver and B6's TLS aggregator). One
new item — a polished multi-protocol monitor example — replaces the
deferred B2 full driver. Section C (long-term) stays parked.
Author's prioritisation (A1 > A2 > A3 > B1) matches ours. The biggest
deviation: we explicitly mark the serde wire vocabulary as a long-term
stability commitment from 0.8 onward — no renames post-release without
a CHANGELOG-documented breaking change.
## 2. Factual notes on the wishlist's credit roll
The wishlist references a `with_flow_tick_interval` builder method;
the actual surface is the `FlowTrackerConfig::flow_tick_interval`
field (set via struct-literal). Minor naming quibble; the underlying
feature shipped correctly in plan 71.
B4's framing — *"`kind.to_string()` returns the full Display rendering
with parameter detail"* — is incorrect: the 0.7 `Display` impl already
returns the short metric-label slug (`"ooo_segment"`, `"buffer_overflow"`).
`short_kind()` ships in this cycle anyway, as the explicit semantic
accessor — but it shadows `Display` rather than fixing a real gap.
The plan documents this explicitly so the choice doesn't read as
duplication.
## 3. What ships in 0.8 (nine plans)
| [`83`](../plans/83-serde-feature.md) | A1 | `serde` opt-in Cargo feature; `Serialize` + `Deserialize` on every public event / message / accessor type; canonical snake_case wire vocabulary locked from 0.8 forward | no (new feature) | 4 d |
| [`84`](../plans/84-icmp-helpers.md) | A2 | `IcmpType::is_error()`, `error_inner() -> Option<(&'static str, &IcmpInner)>`, `short_kind()`; mirrors on `IcmpMessage` | no | 0.5 d |
| [`85`](../plans/85-dns-resolution-cache.md) | A3 | `flowscope::dns::DnsResolutionCache` — TTL'd per-client resolution cache primitive | no | 1 d |
| [`86`](../plans/86-parser-kind-constants.md) | B1 | `PARSER_KIND` / `PARSER_KIND_UDP` / `PARSER_KIND_TCP` constants per parser module + `flowscope::parser_kinds` re-export module | no | 0.2 d |
| [`87`](../plans/87-established-l4.md) | B3 | `FlowEvent::Established { l4: Option<L4Proto> }` — rounds out the trio after plan 79 | **yes** (variant-field) | 0.2 d |
| [`88`](../plans/88-short-kind.md) | B4 | `AnomalyKind::short_kind() -> &'static str` — explicit accessor mirroring the existing `Display` slug | no | 0.1 d |
| [`89`](../plans/89-force-close.md) | B5 | `FlowTracker::force_close()` + driver mirrors + `EndReason::ForceClosed` | no (additive variant) | 0.5 d |
| [`90`](../plans/90-iter-active.md) | B7 | `FlowTracker::iter_active() -> impl Iterator<Item = ActiveFlow<'_, K, S>>` (named-struct entries; replaces / supersedes `all_flow_stats`) | minor (`all_flow_stats` deprecated) | 0.3 d |
| [`91`](../plans/91-multi-protocol-monitor.md) | B2 (recipe) | `examples/multi_protocol_monitor.rs` + SESSION_GUIDE recipe demonstrating the manual multi-parser pattern; full driver deferred to 0.9 RFC | no | 0.5 d |
## 4. Deferred to 0.9+
| B2 — multi-parser composite driver | Sum-type-of-messages requires either macro-generated enums or `Box<dyn Any>` erasure; both have ergonomic costs we want real-world usage data to evaluate. The doc recipe (plan 91) keeps the door open. | RFC for 0.9 after 0.8 ships and netring's `pcap_replay_multi.rs` consumes the recipe. |
| B6 — `TlsHandshake` aggregator | More design surface than the wishlist suggests (resumption / abbreviated handshake / failed handshake / renegotiation). Manual ClientHello+ServerHello correlation pattern works; documented in SESSION_GUIDE. | Revisit after a second consumer asks. |
| C1 — `flowscope::correlate` module | Already RFC-scoped in plan 81. | Continues to ride on the 0.9+ RFC track. |
| C2 — `SequenceDetector` | Part of plan 81. | Same. |
| C3 / C5 / C6 / C7 / C8 | Long-term wishes per author's own framing — *"no netring item depends on them."* | Revisit when a consumer asks specifically. |
| C4 — `HostPair` / `AppliedFilter` extractors | Minor; one-line wishlist mention. | Open separate plans if asked. |
## 5. Where we deviate from the author
### A1 — serde wire vocabulary
Snake_case (as the wishlist suggests) — matches existing metric labels.
Locked from 0.8 forward via:
- `#[serde(rename_all = "snake_case")]` on every public type.
- `#[serde(tag = "type")]` on every public enum (internally-tagged
variants — produces `{"type": "Started", "key": ..., "ts": ...}`).
- Custom `Timestamp` serde impl: emits `{ "sec": u32, "nsec": u32 }`
(preserves precision; symmetric Deserialize works for replay tools).
Once shipped, this is a stability commitment. Renames require a
breaking change with a CHANGELOG migration recipe. Documented at the
top of plan 83.
### B4 — `short_kind()` semantics
We ship the method, but document it as a **semantic alias** for the
string `Display` already returns. Rustdoc and the CHANGELOG both
acknowledge `Display::fmt` returns the same slug — `short_kind()` is
about expressing intent ("I want a metric label") rather than about
fixing a defect in `Display`.
### B7 — `iter_active()` shape
The wishlist proposes `Iterator<Item = (&K, &FlowStats, &S)>`. We ship
`Iterator<Item = ActiveFlow<'_, K, S>>` where `ActiveFlow` is a
`#[non_exhaustive]` named-field struct also carrying `state: FlowState`
and `l4: Option<L4Proto>`. Named fields beat tuples for stability and
clarity; `#[non_exhaustive]` keeps future additions non-breaking.
### B2 — doc recipe, not full driver
Replaces the wishlist's *"if too heavy, ship a recipe"* fallback with
an explicit deliverable (plan 91). Includes a worked example
(`examples/multi_protocol_monitor.rs`) that netring's
`pcap_replay_multi.rs` can model on. Full composite driver gets an
RFC in 0.9.
## 6. Sequencing
Three passes:
1. **Pass A — small additive (plans 86, 88, 90, 84).** Constants, short_kind alias, iter_active, ICMP helpers. No breaking changes. ~1 day total.
2. **Pass B — breaking + additive variant (plans 87, 89, 85).** `Established { l4 }` variant-field; `force_close` + new `EndReason::ForceClosed`; `DnsResolutionCache`. ~2 days.
3. **Pass C — serde (plan 83) + multi-protocol doc/example (plan 91).** Serde is the load-bearing piece; runs last so all types stabilised by passes A+B are covered in one sweep. The multi-protocol example consumes the serde feature to demonstrate JSONL event-stream output. ~5 days.
Total: ~8 implementation days + ~1 day for docs/CHANGELOG/release. About a working week and a half.
## 7. Acceptance bar
flowscope 0.8.0 ships when:
- All nine plans land. `cargo test --all-features` clean. Feature-matrix
CI green (including new `serde` and `serde,l7,pcap` entries).
`cargo doc --all-features --no-deps` zero warnings.
- The serde wire format has golden-file tests proving stability across
every public type. The format is documented in
`docs/OBSERVABILITY.md` → "Structured output via serde".
- `CHANGELOG.md` documents the one breaking change (plan 87 —
`Established { l4 }`), the additive variants (plan 89 —
`EndReason::ForceClosed`), and the deprecation (plan 90 —
`FlowTracker::all_flow_stats` deprecated in favour of `iter_active`).
- `docs/SESSION_GUIDE.md` gains the multi-protocol monitor recipe
(plan 91) and updates for force-close / iter_active patterns.
- `docs/OBSERVABILITY.md` documents the serde wire format + the
`parser_kind` constants.
- Tag `0.8.0` (no `v` prefix; matches `0.1.0` … `0.7.0`).
netring picks up the breaking change + new APIs when it bumps to
flowscope 0.8.
## 8. Open items the author may still revisit
- The credit-roll factual quibbles in §2 — non-blocking, just noted.
- B6 — manual TLS handshake pattern stays the recommendation; revisit
if a second consumer asks.
- C1 / C2 — keep on the 0.9+ RFC track (plan 81).