Skip to content

chore(release): 2.5.0 - #249

Merged
EONRaider merged 2 commits into
masterfrom
claude/release-2.5.0
Oct 25, 2026
Merged

EONRaider merged 2 commits into
masterfrom
claude/release-2.5.0

Conversation

@EONRaider

@EONRaider EONRaider commented Oct 25, 2026 •

Copy link
Copy Markdown
Owner

Summary

Releases Tier 2 of #170 (VRRP, RIP, OSPF, PIM, BGP: #243, #245–#248) as 2.5.0. It adds new public API and removes nothing, so this is a minor version. Every comparative figure in the README was re-measured per Rule 4 of docs/CLAIMS.md.

One headline claim no longer holds and is replaced. "Within 15% of dpkt on decode" is no longer true on the 265-frame corpus: dpkt decodes it 1.27–1.30× faster over three runs.

I ran a file-by-file A/B against the 2.4.0 tree (0a33a5d) on the same machine to find out why:

  • On the five new routing captures, dpkt is 1.46× faster. dpkt decodes OSPF, PIM and VRRP to the same layer as netprotocols.
  • On the 140 frames 2.4.0 was measured on, the two are within 10% of each other on both trees. 2.4.0's own --compare, re-run here, still reads 1.03×.

So the gap comes from the new workload, not from a code regression. I didn't profile why dpkt is faster on those protocols; that's #250.

The README bullet now quotes 1.3× and says where the gap comes from, and CLAIMS 1.2 is renamed to the figure it now holds.

What's included

  • Version: 2.4.0 → 2.5.0 in pyproject.toml, __version__ and uv.lock.

  • CHANGELOG: [Unreleased] becomes [2.5.0] - 2026-10-25, with Development entries for the re-measurement and the benchmark baseline.

  • README "Why":

    Claim 2.4.0 2.5.0
    Decode vs scapy 4.1× faster 3.4× faster
    Decode vs dpkt within 15% dpkt 1.3× faster
    Decoded deeper than dpkt 39 of 140 frames 79 of 265 frames
    Encode vs dpkt 4.2× faster 4.6× faster
    Import (netprotocols vs scapy.all) 55 ms vs 428 ms 70 ms vs 397 ms
    Wheel size 124.4 KiB, 21.7× smaller than scapy 176.5 KiB, 15.3× smaller

    The 40 frames newly decoded deeper are BGP's 19 and RIP's 21, which dpkt leaves as raw bytes.

  • README roadmap: names 2.5.0 and links feat(layer3): decode VRRPv2 and VRRPv3, dispatched from IP protocol 112 #243 and feat(layer7): decode RIPv1 and RIPv2, dispatched from UDP port 520 #245–feat(layer7): decode BGP-4 messages dispatched from TCP port 179 #248.

  • docs/CLAIMS.md:

    • a new "Re-measured for 2.5.0" section, with each run, the per-file table and the A/B;
    • dated lines under claims 1.1–1.6;
    • claim 1.2 renamed and 1.4 retitled;
    • a §6 addendum.
  • benchmarks/baseline.json re-recorded (3fed671): from 2.2.1 on 97 frames (normalized 6.5677) to 2.5.0 on 265 frames (5.4344).

Why the benchmark baseline was re-recorded

The CI benchmark gate failed on this PR's first head (54afd75): -17.1%, then -16.5% on its own retry, against a 15% threshold. This PR changes no library code. The same tree minus the version bump (master at 03387af) passed that job ten minutes earlier at -14.1%.

The cause is the baseline. It was recorded at 2.2.1 on the 97-frame corpus, and the gate walks the whole corpus, now 265 frames. Tier 1 and Tier 2 added captures that cost more per frame, so the gate drifted to its own threshold and runner noise decided the result.

The reviewer's A/B shows no code regression across the span the old baseline covered. On the same CPython 3.12.3 with 30 repetitions and best of 9, over six alternating rounds:

Comparison Corpus f/s change
2.5.0 vs 2.2.1 2.2.1's 97 frames +3.0%
2.5.0 vs 2.4.0 2.4.0's 140 frames -2.1%
Workload, 97 → 265 frames 2.5.0 code throughout -16.7%

The -16.7% workload drop matches CI's -17.1%.

Per the steward rule (.claude/skills/steward/SKILL.md), an independent agent made the fix and another independent agent reviewed and approved it. The fixer re-recorded with the script's own --update-baseline, using the settings the gate reuses (30 repetitions, best of 9). The recorded value sits at the median of the surrounding runs, not at an outlier. The threshold, the CI job and benchmark.py are unchanged.

Re-anchoring accepts the drift since 2.2.1. From here, the gate guards against regressions relative to 2.5.0 on this corpus.

Verification

  • uv run ruff check and uv run ruff format --check are clean
  • uv run mypy is clean (strict)
  • uv run pytest passes locally: 4743 passed
  • CHANGELOG.md has an entry for 2.5.0
  • The CI benchmark command, run locally after the re-record, read between -3.4% and +8.4% over six runs, all within the threshold.
  • Measured on CPython 3.12.3 (Intel Xeon @ 2.10 GHz, 4 vCPUs) against dpkt 1.9.8 and scapy 2.8.0, the versions the lock pins:
    • decode: benchmark.py --compare --repetitions 30 --trials 9, three runs;
    • encode: benchmark_encode.py;
    • import: benchmark_import.py, best of three;
    • depth: benchmark.py --depth.
  • uv build --wheel on a git archive of the release commit produced netprotocols-2.5.0-py3-none-any.whl at 180,744 bytes, identical across repeated builds. The baseline commit changes no file that ships in the wheel.

Notes

  • Tag order: v2.4.0 hasn't been tagged yet. It needs pushing at 0a33a5d before v2.5.0 is pushed at this PR's merge commit.
  • Import time grew by 15 ms. The five new modules define 27 frozen dataclasses, which are generated at import.
  • Follow-up: perf: profile and narrow the decode gap to dpkt on OSPF, BGP and PIM #250 covers profiling and narrowing the decode gap on OSPF, BGP and PIM.

🤖 Generated with Claude Code

https://claude.ai/code/session_01CEQCZGyuvpMyZwUbDucF3G

Tier 2 of #170 (VRRP, RIP, OSPF, PIM, BGP: #243, #245-#248) ships as
2.5.0: new public API, no removals, so a minor version.

- pyproject.toml, __version__ and uv.lock: 2.4.0 -> 2.5.0.
- CHANGELOG: [Unreleased] becomes [2.5.0] - 2026-10-25, with a
  Development entry for the re-measurement.
- README and docs/CLAIMS.md: every comparative number re-measured per
  Rule 4 on the 265-frame corpus, against dpkt 1.9.8 and scapy 2.8.0.
  "Within 15% of dpkt on decode" no longer holds: dpkt decodes the
  corpus 1.27-1.30x faster over three runs. A file-by-file A/B against
  the 2.4.0 tree (0a33a5d) puts the gap in the five routing captures
  (dpkt 1.46x faster on them); the 140 frames 2.4.0 was measured on
  read within 10% on both trees, so it is the workload, not a
  regression. The README bullet now quotes the 1.3x and says where it
  comes from, and CLAIMS 1.2 is renamed for the figure it holds.
  Scapy 3.4x (from 4.1x), encode 4.62x, import 70.0 ms against
  scapy.all's 396.9 ms (from 55.0 ms; five more modules), depth 79 of
  265 (the 40 new are BGP and RIP). The wheel figure, 180,744 bytes
  (15.3x smaller), comes from `uv build --wheel` on a `git archive` of
  this commit.
- README roadmap: names 2.5.0 and links #243 and #245-#248.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CEQCZGyuvpMyZwUbDucF3G
@coderabbitai

coderabbitai Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 22 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: 0f7333ff-1f4b-45c5-84d7-d1175cd124ad
Commits

Reviewing files that changed from the base of the PR and between 03387af and 3fed671.

Files ignored due to path filters: 1
  • uv.lock is excluded by !**/*.lock
Files selected for processing: 6
  • CHANGELOG.md
  • README.md
  • benchmarks/baseline.json
  • docs/CLAIMS.md
  • pyproject.toml
  • src/netprotocols/__init__.py
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

The benchmark job failed on the 2.5.0 release PR at -17.1% (then
-16.5% on its re-measure) against a baseline recorded at 2.2.1 on the
97-frame corpus (6.5677 normalized). The PR changes no library code,
and the same code passed on master (03387af) at -14.1% ten minutes
earlier: the gate was sitting on its own 15% threshold and runner
noise picked the side.

The drop is the workload. --check walks every tests/fixtures/*.pcap,
now 265 frames, and the Tier 1 and Tier 2 captures cost more per frame
than the old ones. The file-by-file A/B of 2.4.0 against 2.5.0 in
docs/CLAIMS.md shows no regression beyond that harness's noise on the
140 frames 2.4.0 had.

Re-recorded with `benchmark.py --repetitions 30 --trials 9
--update-baseline` on CPython 3.12.3: 5.4344 normalized (97,453 f/s).
Four probe runs beforehand read 5.48, 5.28, 5.72 and 5.29, so the
recording sits at their median rather than an outlier. Three local
runs of the CI command then read +3.8%, +4.3% and -3.4%.

Re-anchoring accepts the drift since 2.2.1; the gate now guards
against regressions relative to 2.5.0 on this corpus. The threshold,
the CI job and benchmark.py are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CEQCZGyuvpMyZwUbDucF3G
@EONRaider
EONRaider merged commit 7549dc0 into master Oct 25, 2026
16 checks passed
@EONRaider
EONRaider deleted the claude/release-2.5.0 branch October 25, 2026 04:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants