flowscope 0.7.0

Passive flow & session tracking for packet capture (runtime-free, cross-platform)
Documentation
# flowscope 0.7 — Plan of record

**Date:** 2026-05-29
**Source:** [`docs/feedback-2026-05-29-netring-round2.md`](./feedback-2026-05-29-netring-round2.md)
— second-round netring feedback after writing four real-life L7
examples (`multi_protocol_monitor`, `http_session`, `dns_lookups`,
`full_monitor`).
**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 round-2 feedback is short by design — the author credits 0.5/0.6
with absorbing 10 of the 12 items from round 1 (one factual quibble
noted below). The remaining proposals come from real
post-implementation usage rather than pre-integration speculation,
which makes them more concrete and easier to evaluate.

We adopt seven of the nine round-2 proposals for 0.7.0, defer one
big item (F6) to an RFC for 0.8 implementation per the author's own
recommendation, and defer one bigger item (F7) until after F6 ships
and downstream usage clarifies the API needs.

The author's prioritization order (F1 > F6 > F4 > F3) closely
matches ours. The biggest deviation: we reverse the 0.6 decline of
`is_done()` (F5/round-1 #10) — the round-2 expanded use cases are
strong enough to justify the additive surface.

## 2. Factual correction in the round-2 credit roll

The feedback credits item 2 from round 1 (`with_auto_sweep`) as
shipped in 0.5.0 via `flow_tick_interval` / `FlowEvent::Tick`.
**This is not accurate.** `flow_tick_interval` (plan 71) ships
informational *tick emission* — it never closes flows. The original
item 2 was about *sweep cadence* — implicit `Ended` events fired
from packet-clock advancement.

The two features are independent. Sweep-cadence remains deferred
and is now scoped in [`../plans/75-rfc-tracker-auto-sweep.md`](../plans/75-rfc-tracker-auto-sweep.md)
(RFC only; implementation in 0.8.0+).

The author can refresh their credit roll to reflect this when the
0.7 series ships.

## 3. What ships in 0.7 (seven plans + one RFC + one carried)

| Plan | Item(s) | Change | Breaking? | Effort |
|------|---------|--------|-----------|--------|
| [`62`]../plans/62-intra-doc-recipe-in-published-docs.md | F8 (= round-1 #12) | Move intra-doc-link recipe from `CLAUDE.md` into `docs/SESSION_GUIDE.md` | no | 30 min |
| [`76`]../plans/76-icmp-parser.md | F1 | `flowscope::icmp::IcmpParser` (`DatagramParser`-shaped); wraps `etherparse` types; `IcmpInner` for error-message correlation | no (new feature `icmp`) | 1 day |
| [`77`]../plans/77-display-impls.md | F2 | `impl Display` on `L4Proto`, `EndReason`, `AnomalyKind` — match the existing metric labels | no | 1 h |
| [`78`]../plans/78-http-tls-accessors.md | F3 | `HttpRequest::{host, user_agent, cookie, header}`, mirrors on `HttpResponse`, `TlsClientHello::sni()` | no | 4 h |
| [`79`]../plans/79-ended-l4-field.md | F4 | `FlowEvent::Ended { l4: Option<L4Proto> }` + `SessionEvent::Closed { l4 }` | **yes** (variant-field add) | 1 h |
| [`80`]../plans/80-session-parser-is-done.md | F5 (= round-1 #10) | `SessionParser::is_done()` + `DatagramParser::is_done()` + `EndReason::ParserDone` | no (additive variant in `#[non_exhaustive]`) | 4 h |
| [`82`]../plans/82-anomaly-severity.md | F9 | `AnomalyKind::severity() -> Severity` (4 levels: `Info`/`Warning`/`Error`/`Critical`) | no | 1 h |

## 4. Deferred to 0.8.0+

| Item | Why deferred | Tracked at |
|------|--------------|------------|
| F6 — `flowscope::correlate` module | API design space is wide (`TimeBucketedCounter`, `KeyIndexed`, `SequencePattern` traits); the author themselves requested an RFC first | [`81-rfc-correlate-module.md`]../plans/81-rfc-correlate-module.md — RFC scope only; the author has offered to co-author |
| F7 — `DnsResolutionCache` / cross-protocol key derivation | Author's own framing: *"the right shape probably emerges only after writing 2–3 anomaly examples manually first"*; not RFC-ready | Footnote in `plans/INDEX.md`; revisit after F6 implementation experience |
| Round-1 #2 — `FlowTracker::with_auto_sweep(interval)` | Pre-existing deferral; RFC already scoped | [`75-rfc-tracker-auto-sweep.md`]../plans/75-rfc-tracker-auto-sweep.md |
| Round-1 #14 (F2.4) — OOO TCP reassembly | Pre-existing deferral; RFC already scoped | [`74-rfc-ooo-reassembly.md`]../plans/74-rfc-ooo-reassembly.md |

## 5. Where we disagree with the author

### F2 — Display formatting

The feedback proposes uppercase labels (`TCP`, `UDP`, `ICMP`,
`SCTP`). We ship **lowercase** to match the existing metric label
vocabulary (`obs.rs::l4_label` already returns `"tcp"`/`"udp"`).
Consumers that want uppercase write `.to_string().to_ascii_uppercase()`;
consumers wanting metric-compatible labels (the more common case)
get them for free.

This is a small reversal of the author's proposal; if they push
back we'd flip without resistance. The case-folding tax is
symmetric.

### F5 — `EndReason` variant name

The feedback proposes `EndReason::ParserClosed`. We ship
`EndReason::ParserDone`. *"Done"* reads more naturally next to
`Fin` (also a completion state) and avoids confusion with
*"the parser was forcibly closed"* (which is what `ParseError`
already means).

### F9 — `Severity` levels

The feedback proposes `Info` / `Warn` / `Error` / `Critical` (slog
tradition). We adopt **`Info` / `Warning` / `Error` / `Critical`**
— `Warning` over `Warn` to match the spelled-out spelling that
`tracing` and most logging frameworks use. Trivial naming
preference; happy to flip if the author objects.

## 6. Sequencing

Two passes:

1. **Pass A — small additive (plans 62, 77, 78, 80, 82).** No
   breaking changes; can ship in any order. ~6 hours total.
2. **Pass B — single-field break (plan 79) + new feature batch
   (plan 76 ICMP).** Pass A first because the small surface
   stabilises tests against the new accessors before the L4
   field migration touches every `match` on `Ended`. ~9 hours
   total.

Total: ~15 implementation hours + ~3 hours docs / CHANGELOG /
release. Two-day batch if focused.

**RFCs (plans 81, 75, 74)** ship as documents only — no code in
0.7. Implementation when consumer + maintainer agree on the
design.

## 7. Acceptance bar

flowscope 0.7.0 ships when:

- All seven plans above land, `cargo test --all-features` clean,
  feature-matrix CI green, `cargo doc --all-features --no-deps`
  clean.
- `CHANGELOG.md` has migration notes for plan 79's variant-field
  break.
- `docs/SESSION_GUIDE.md` reflects the new accessor surface
  (plan 78) and the `is_done()` lifecycle hook (plan 80).
- `docs/OBSERVABILITY.md` documents `Severity` and how it routes
  the `flowscope.anomaly` tracing target (plan 82).
- Tag `0.7.0` (no `v` prefix; matches `0.1.0``0.6.0`).

netring picks up the breaking change (plan 79) and the new
parser modules (`icmp`) when it bumps to flowscope 0.7.

## 8. Open items the author may still revisit

- The factual quibble in §2.
- F6 — the author offered to draft the RFC; plan 81 documents
  what flowscope expects from that draft.
- F7 — not yet RFC-ready; revisit after the first 2–3 anomaly
  examples land in netring against the F6 correlate primitives.