Skip to content

refactor(foundation): declare _CODE_DESTINATIONS as a dunder on the enum registries themselves - #2403

Merged
JarryShaw merged 1 commit into
mainfrom
feat/2392-code-destinations-dunder-v2
Oct 28, 2026
Merged

JarryShaw merged 1 commit into
mainfrom
feat/2392-code-destinations-dunder-v2

Conversation

@JarryShaw

Copy link
Copy Markdown
Owner
  • Searched for similar pull requests
  • Followed the coding style
  • make test passes, and a test case covers the change
  • Changelog entry: regenerated CHANGELOG.md (one phrase naming _CODE_DESTINATIONS, which won't exist in 1.5.0)

What is the purpose of your pull request?

  • refactor — code refactoring

Description

Follow-up to #2392, answering your question there: "Possible to deprecate _CODE_DESTINATIONS as well?"

  • Problem: _CODE_DESTINATIONS mapped an enum registry type to the protocol class(es) owning the __proto__ dispatch registry keyed by that enum, so register_protocol_code could infer a destination from a bare enum member. Mirrors __proto_key__, which refactor(foundation): declare each registry's code kind as a class attribute, not a module table (#2343) #2392 moved the opposite direction (destination → enum) onto the destination classes themselves.
  • Fix: each of the 4 enum registry classes (EtherType, TransType, LinkType, PayloadProtocolIdentifier) now declares __proto_dest__, a tuple of ModuleDescriptor naming its destination class(es) lazily. const sits below protocols in the dependency order, so a real class reference would make const import protocols; ModuleDescriptor (already used for __proto__ dispatch tables elsewhere) avoids that without inventing a parallel string-path scheme. _iter_code_targets reads the dunder off type(code) via getattr() and resolves each descriptor's .klass.
  • getattr(), not vars(): verified aenum refuses to extend an enumeration that already has members, so none of these four registries can gain a subclass with its own registry — the hazard __proto_key__'s vars() call guards against (Loopback/IPX owning a differently-keyed registry) is structurally impossible here. Where an enum registry is subclassed (AppType → TCP/UDP/SCTP/DCCP), the base has no members and the parts share one key space, so inheriting the pairing is correct.
  • Regenerated, not hand-edited: const/reg/*.py and const/sctp/payload_protocol_identifier.py are template output. The vendor crawlers gain a PROTO_DEST class attribute, threaded through vendor/default.py's LINE template and context(); verified by recovering each committed file's ENUM/MISS blocks and re-rendering through the unmodified template first (byte-identical to the committed file) before re-rendering with PROTO_DEST — so the diff is provably just the template's effect.
  • Test: tests/vendor/test_vendor_proto_dest_2392_unit.py (new), plus ProtoDestDeclarationTests in test_protocol_code_registration_unit.py and an update to test_dispatch_reachability_unit.py, which read the dunder instead of the deleted dict.

@JarryShaw JarryShaw added refactor Restructuring for its own sake — neither a fix nor a new capability (refactor: prefix) const Regenerated IANA or vendor constant tables; members keep their numeric values review: running A cross-review is in flight against the current head - no verdict yet labels Oct 27, 2026
@github-actions github-actions Bot added this to the PyPCAPKit v1.5 milestone Oct 27, 2026
@JarryShaw JarryShaw moved this to In review in PyPCAPKit Oct 27, 2026
@JarryShaw

Copy link
Copy Markdown
Owner Author

Review: GOOD TO GO at 99d1669ce (Sonnet). All six verification points independently re-derived: getattr() vs vars() confirmed equivalent today — real aenum rejects any subclass of these 4 registries unconditionally, with or without members (TypeError: cannot extend), and of 151 pcapkit enums the only subclassed bases (AppType, httpv2 Flags) are memberless. Const files confirmed genuine template output: driving Vendor.__init__ offline with network/parsing stubbed reproduces both origin/main's files (with PROTO_DEST=()) and this PR's files (with each crawler's real PROTO_DEST) byte-for-byte, 4/4 each way. No import cycle (corekit.module's closure equals corekit.enum's, already imported everywhere). Exact parity with the old dict across all 605 enum members including the Frame/PCAPNG fan-out. 342 passed/2680 subtests, 0 skipped; 5/5 planted mutations caught by the new tests; no new mypy/pylint diagnostics.

Three small non-blocking nits, fixing now:

  • The protocols.py comment claiming AppType's parts "would rightly share one destination" is imprecise — register_apptype routes by each member's own transport, so a single class-level destination would be wrong there; it's moot only because AppType declares none.
  • "inference table" is stale phrasing in two test docstrings (test_protocol_code_registration_unit.py lines ~151, ~309) — a leftover from the dict-based mechanism this PR replaced.
  • The commit title says feat( while the label and tickbox say refactor (refactor(foundation): declare each registry's code kind as a class attribute, not a module table (#2343) #2392 used refactor( for the analogous change) — minor consistency nit.

@JarryShaw JarryShaw added review: good-to-go Cross-review at the current head says ready; CI state is separate and removed review: running A cross-review is in flight against the current head - no verdict yet labels Oct 27, 2026
…num registries themselves

Follow-up to #2392/#2343. _CODE_DESTINATIONS was a module-level dict
mapping an enum registry type to the protocol class(es) owning the
__proto__ dispatch registry keyed by that enum, so register_protocol_code
could infer a destination from a bare enum member. Mirrors __proto_key__,
which #2392 moved the opposite direction (destination -> enum) onto the
destination classes themselves.

Each of the 4 enum registry classes (EtherType, TransType, LinkType,
PayloadProtocolIdentifier) now declares __proto_dest__, a tuple of
ModuleDescriptor naming its destination class(es) lazily -- const sits
below protocols in the dependency order, so a real class reference would
make const import protocols; ModuleDescriptor (already used for __proto__
dispatch tables elsewhere) avoids that without inventing a parallel
string-path scheme. _iter_code_targets reads the dunder off type(code)
via getattr() and resolves each descriptor's .klass.

getattr(), not vars(): verified aenum refuses to extend an enumeration
that already has members, so none of these four registries can gain a
subclass with its own registry -- the hazard __proto_key__'s vars() call
guards against (Loopback/IPX owning a differently-keyed registry) is
structurally impossible here. The one enum registry that is subclassed,
AppType, is irrelevant here only because it declares no __proto_dest__
at all -- a class-level destination would in fact be the wrong model for
it, since register_apptype routes each member to the registry named by
that member's own transport protocol, which no single shared destination
could express.

const/reg/*.py and const/sctp/payload_protocol_identifier.py are
regenerated, not hand-edited: the vendor crawlers (vendor/reg/*.py,
vendor/sctp/payload_protocol_identifier.py) gain a PROTO_DEST class
attribute, threaded through vendor/default.py's LINE template and
context(); a throwaway script recovered each committed file's ENUM/MISS
blocks and re-rendered through the unmodified template first, asserting
byte-identity with the committed file, before re-rendering with
PROTO_DEST to confirm the diff is purely the template's effect.

Tests: tests/vendor/test_vendor_proto_dest_2392_unit.py (new) plus
ProtoDestDeclarationTests in test_protocol_code_registration_unit.py and
an update to test_dispatch_reachability_unit.py, which read the dunder
instead of the deleted dict.
@JarryShaw
JarryShaw force-pushed the feat/2392-code-destinations-dunder-v2 branch from 99d1669 to 3355d73 Compare October 27, 2026 23:27
@JarryShaw JarryShaw changed the title feat(foundation): declare _CODE_DESTINATIONS as a dunder on the enum registries themselves refactor(foundation): declare _CODE_DESTINATIONS as a dunder on the enum registries themselves Oct 27, 2026
@JarryShaw

Copy link
Copy Markdown
Owner Author

Amended 99d1669ce → 3355d7317: fixed all three nits. Reworded the AppType comment in protocols.py to say precisely why it's irrelevant (declares no __proto_dest__ at all — a class-level destination would in fact be wrong for it, since register_apptype routes each member by its own transport). Reworded the two stale "inference table" references in test_protocol_code_registration_unit.py (lines ~151, ~309) to describe the new __proto_dest__ mechanism. Retitled the commit/PR from feat( to refactor( for consistency with #2392. 83 passed/543 subtests, unchanged.

@github-actions

Copy link
Copy Markdown
Contributor

Coverage: 91.67% (unit tier, Python 3.15, 3355d7317, Unit Tests run success)

Package Statements Missed Branches Partial Cover
pcapkit (top level) 104 4 20 2 95.16%
pcapkit/const 19609 880 2620 867 92.12%
pcapkit/corekit 2596 74 818 37 96.51%
pcapkit/dumpkit 282 3 102 3 98.44%
pcapkit/foundation 3045 24 1062 26 98.78%
pcapkit/interface 138 4 52 3 96.32%
pcapkit/protocols 17574 210 4666 196 98.17%
pcapkit/toolkit 924 36 334 10 95.55%
pcapkit/utilities 502 7 144 5 98.14%
pcapkit/vendor 4449 1961 1020 167 52.64%

Per-file detail: the coverage-html artifact of this run.

@JarryShaw
JarryShaw merged commit d31cd1c into main Oct 28, 2026
61 checks passed
@JarryShaw
JarryShaw deleted the feat/2392-code-destinations-dunder-v2 branch October 28, 2026 01:52
@github-project-automation github-project-automation Bot moved this from In review to Done in PyPCAPKit Oct 28, 2026
@JarryShaw JarryShaw removed the review: good-to-go Cross-review at the current head says ready; CI state is separate label Oct 28, 2026
JarryShaw added a commit that referenced this pull request Oct 28, 2026
…egistry and registration prose (#1103)

#1103 whole-repo prose sweep over the maker-message wave (#2296, #2404, #2405,
#2407) and the __proto_dest__ registry refactor (#2392, #2403).

Docstrings corrected where the prose did not match the code:

* ``Protocol`` -> ``ProtocolBase`` in the ``register``/``register_protocol``
  cross-references (protocol.py, internet.py, link.py, transport.py, sctp.py,
  registry/protocols.py).
* ``Raises:`` entries for the ``bool`` port guard (#2287) in TCP, UDP and SCTP
  ``make``, and for HTTP/1's request-without-``uri`` guard.
* ``protochain`` documented on both sides of its narrowing to ``None``
  (protocol.py, misc/null.py, #2317), and ``__init__`` names the
  ``__own_make_keywords__`` exception to its keyword check.
* IP reassembly names the IPv6 ``M`` bit and which buffer an atomic fragment is
  isolated from (#2270); ``_check_code`` names ``register_protocol_code`` among
  its callers (#2186).
* HIP's shared lifetime helper says where the octet appears instead of counting
  the makers that carry it, and ``_make_opt_pad`` warns and makes a ``PadN``
  rather than raising as its reader does.

Before/after narration replaced with present tense, the pattern #1103's round 6
banned: the ``__proto_dest__`` prose in the registration and vendor tests, and
the #2296 maker-message module docstring.

AST guard (``ast.dump`` via util/vendor_code_changed.py's ``code_of``, with
docstrings and bare string literals stripped) confirms all 16 touched files are
prose-only against e48062c. 135 tests and 334 subtests pass across the four
touched test modules, tests/test_docstring_contract.py, and the convention and
issue/PR-role guards in tests/project/.
JarryShaw added a commit that referenced this pull request Oct 28, 2026
…egistry and registration prose (#1103)

#1103 whole-repo prose sweep over the maker-message wave (#2296, #2404, #2405,
#2407) and the __proto_dest__ registry refactor (#2392, #2403).

Docstrings corrected where the prose did not match the code:

* ``Protocol`` -> ``ProtocolBase`` in the ``register``/``register_protocol``
  cross-references (protocol.py, internet.py, link.py, transport.py, sctp.py,
  registry/protocols.py).
* ``Raises:`` entries for the ``bool`` port guard (#2287) in TCP, UDP and SCTP
  ``make``, and for HTTP/1's request-without-``uri`` guard.
* ``protochain`` documented on both sides of its narrowing to ``None``
  (protocol.py, misc/null.py, #2317), and ``__init__`` names the
  ``__own_make_keywords__`` exception to its keyword check.
* IP reassembly names the IPv6 ``M`` bit and which buffer an atomic fragment is
  isolated from (#2270); ``_check_code`` names ``register_protocol_code`` among
  its callers (#2186).
* HIP's shared lifetime helper says where the octet appears instead of counting
  the makers that carry it, and ``_make_opt_pad`` warns and makes a ``PadN``
  rather than raising as its reader does.

Before/after narration replaced with present tense, the pattern #1103's round 6
banned: the ``__proto_dest__`` prose in the registration and vendor tests, the
``register_protocol_code`` key-check narration, and the #2296 and #2406
maker-message module docstrings.

AST guard (``ast.dump`` via util/vendor_code_changed.py's ``code_of``, with
docstrings and bare string literals stripped) confirms all 16 touched files are
prose-only against e48062c. 130 tests and 334 subtests pass across the four
touched test modules, tests/test_docstring_contract.py, and
tests/project/test_conventions_doc_claims.py,
tests/project/test_docs_issue_pr_roles_1103_unit.py and
tests/project/test_issue_refs_in_comments.py.
JarryShaw added a commit that referenced this pull request Oct 28, 2026
…egistry and registration prose (#1103)

#1103 whole-repo prose sweep over the maker-message wave (#2296, #2404, #2405,
#2407) and the __proto_dest__ registry refactor (#2392, #2403).

Docstrings corrected where the prose did not match the code:

* ``Protocol`` -> ``ProtocolBase`` in the ``register``/``register_protocol``
  cross-references (protocol.py, internet.py, link.py, transport.py, sctp.py,
  registry/protocols.py).
* ``Raises:`` entries for the ``bool`` port guard (#2287) in TCP, UDP and SCTP
  ``make``, and for HTTP/1's request-without-``uri`` guard.
* ``protochain`` documented on both sides of its narrowing to ``None``
  (protocol.py, misc/null.py, #2317), and ``__init__`` names the
  ``__own_make_keywords__`` exception to its keyword check.
* IP reassembly names the IPv6 ``M`` bit and which buffer an atomic fragment is
  isolated from (#2270); ``_check_code`` names ``register_protocol_code`` among
  its callers (#2186).
* HIP's shared lifetime helper says where the octet appears instead of counting
  the makers that carry it, and ``_make_opt_pad`` warns and makes a ``PadN``
  rather than raising as its reader does.

Before/after narration replaced with present tense, the pattern #1103's round 6
banned:

* the ``__proto_dest__`` prose in the registration and vendor tests, and the
  ``register_protocol_code`` key-check narration;
* the #2296 and #2406 maker-message module docstrings -- readers are exempt by
  design rather than "deliberately untouched", and the HTTP ``frame=None`` case
  is outside the guard rather than one the guard "has not widened to";
* the ``_NameLease`` rationale and the ``register_protocol`` name-collision
  note in registry/protocols.py, which described a fix and a redesign in the
  past tense;
* TCP's ``_make_mptcp_unknown`` length comment, which contrasted the current
  expression with "the former" one.

AST guard (``ast.dump`` via util/vendor_code_changed.py's ``code_of``, with
docstrings and bare string literals stripped) confirms all 16 touched files are
prose-only against e48062c. 129 tests pass (1 pre-existing skip) with 334
subtests across the four touched test modules, tests/test_docstring_contract.py,
tests/project/test_conventions_doc_claims.py,
tests/project/test_docs_issue_pr_roles_1103_unit.py and
tests/project/test_issue_refs_in_comments.py.
JarryShaw added a commit that referenced this pull request Oct 28, 2026
Problem: of the 60 pull requests merged in the #2312-#2407 range, only
#2334, #2336, #2337, #2340 and #2348 wrote a 1.5.0 changelog entry, and
#2398 and #2403 only reworded lines that were already there. Every other
user-visible change in the range -- wire-semantics fixes, maker guards,
reassembly behaviour, public-API and error-message changes -- went
unrecorded, so the entry no longer describes the release.

Fix: one entry per user-visible pull request, in each module section's
existing style and ordered by the issue it closes. Two pairs share a
bullet, since each is the direct follow-up of the other: #2393 with
#2401, and #2405 with #2407. The diff on the entry file is purely
additive.

Internal-only work is left out deliberately: dependency and action bumps
(#2387 to #2391), test-only and docs-prose passes (#2333, #2376, #2379,
#2380, #2402), the unreachable-branch removal (#2378), and the #: comment
marker the HIP Group and Packet crawlers now write (#2381). That last one
renders nothing either way: the marker lands inside the generated
_missing_ body, conf.py's exclude-members drops _missing_ from autodoc,
and a comment in a method body is not an attribute comment to begin with.

#2392 and #2403 are recorded together, under Added rather than Fixed, for
the declarations they introduce: __proto_key__ on the seven classes owning
a __proto__ registry (#2392), __proto_dest__ on the four enum registries
and Vendor.PROTO_DEST to generate it (#2403). Both PRs added the autodoc
entries, so both are rendered public attributes. #2392's rejection-message
change is deliberately not recorded as a fix: the bare "code must be ..."
text it prefixed came from _check_code, which #2193 introduced and which
is in no release tag -- absent at v1.5.0b14 -- so no released version ever
emitted it. #2403 is no longer skipped as internal because it reworded an
existing bullet to name __proto_dest__ while nothing credited the
attribute's introduction.

Four claims are corrected against the source rather than carried over:
FTP_DATA shipped in pcapkit/protocols/application/ftp.py from 1.0.0, not
1.4.0 (class FTP_DATA(Raw) is there at v1.0.0); #2365's pre-fix fallback
read cmmd.value, so a .value-carrying object was accepted unchecked
rather than raising; #2399 left the dpkt adapter and the adapters'
ModuleNotFound raises alone, so it claims no universal prefix; and
#2397's old tail did name the version it got, so the entry quotes it and
gains the :issue:`2302` it was missing. #2370's "a Section Header Block
... still fails" sentence is dropped: #2369 settles the byte order first,
and an SHB built from raw octets with ctx=None now rebuilds byte-exact in
both byte orders.

CHANGELOG.md is regenerated with util/changelog_md.py.

Test: tests/project/ in full, 0 failures, including test_changelog_md.py's
in-step and supported-subset checks; util/changelog_md.py --check reports
the two files in step; the entry parses under docutils with no structural
warning.
JarryShaw added a commit that referenced this pull request Oct 28, 2026
…egistry and registration prose (#1103)

#1103 whole-repo prose sweep over the maker-message wave (#2296, #2404, #2405,
#2407) and the __proto_dest__ registry refactor (#2392, #2403).

Docstrings corrected where the prose did not match the code:

* ``Protocol`` -> ``ProtocolBase`` in the ``register``/``register_protocol``
  cross-references (protocol.py, internet.py, link.py, transport.py, sctp.py,
  registry/protocols.py).
* ``Raises:`` entries for the ``bool`` port guard (#2287) in TCP, UDP and SCTP
  ``make``, and for HTTP/1's request-without-``uri`` guard.
* ``protochain`` documented on both sides of its narrowing to ``None``
  (protocol.py, misc/null.py, #2317), and ``__init__`` names the
  ``__own_make_keywords__`` exception to its keyword check.
* IP reassembly names the IPv6 ``M`` bit and which buffer an atomic fragment is
  isolated from (#2270); ``_check_code`` names ``register_protocol_code`` among
  its callers (#2186).
* HIP's shared lifetime helper says where the octet appears instead of counting
  the makers that carry it, and ``_make_opt_pad`` warns and makes a ``PadN``
  rather than raising as its reader does.

Before/after narration replaced with present tense, the pattern #1103's round 6
banned:

* the ``__proto_dest__`` prose in the registration and vendor tests, and the
  ``register_protocol_code`` key-check narration;
* the #2296 and #2406 maker-message module docstrings -- readers are exempt by
  design rather than "deliberately untouched", and the HTTP ``frame=None`` case
  is outside the guard rather than one the guard "has not widened to";
* the ``_NameLease`` rationale and the ``register_protocol`` name-collision
  note in registry/protocols.py, which described a fix and a redesign in the
  past tense;
* TCP's ``_make_mptcp_unknown`` length comment, which contrasted the current
  expression with "the former" one.

AST guard (``ast.dump`` via util/vendor_code_changed.py's ``code_of``, with
docstrings and bare string literals stripped) confirms all 16 touched files are
prose-only against e48062c. 129 tests pass (1 pre-existing skip) with 334
subtests across the four touched test modules, tests/test_docstring_contract.py,
tests/project/test_conventions_doc_claims.py,
tests/project/test_docs_issue_pr_roles_1103_unit.py and
tests/project/test_issue_refs_in_comments.py.
JarryShaw added a commit that referenced this pull request Oct 28, 2026
Problem: of the 60 pull requests merged in the #2312-#2407 range, only
#2334, #2336, #2337, #2340 and #2348 wrote a 1.5.0 changelog entry, and
#2398 and #2403 only reworded lines that were already there. Every other
user-visible change in the range -- wire-semantics fixes, maker guards,
reassembly behaviour, public-API and error-message changes -- went
unrecorded, so the entry no longer describes the release.

Fix: one entry per user-visible pull request, in each module section's
existing style and ordered by the issue it closes. Three pairs share a
bullet, since each is the direct follow-up or counterpart of the other:
#2393 with #2401, #2405 with #2407, and #2392 with #2403. The diff on the
entry file is purely additive.

Internal-only work is left out deliberately: dependency and action bumps
(#2387 to #2391), test-only and docs-prose passes (#2333, #2376, #2379,
#2380, #2402), the unreachable-branch removal (#2378), and the #: comment
marker the HIP Group and Packet crawlers now write (#2381). That last one
renders nothing either way: the marker lands inside the generated
_missing_ body, conf.py's exclude-members drops _missing_ from autodoc,
and a comment in a method body is not an attribute comment to begin with.

#2392 and #2403 are recorded together, under Added rather than Fixed, for
the declarations they introduce: __proto_key__ on each class owning a
__proto__ registry (#2392), __proto_dest__ on the enum registries and
Vendor.PROTO_DEST to generate it (#2403). The bullet names those classes
and registries rather than counting them, per the no-counted-numbers rule
for the unreleased entry. Both PRs added the autodoc entries, so both are
rendered public attributes. #2392's rejection-message
change is deliberately not recorded as a fix: the bare "code must be ..."
text it prefixed came from _check_code, which #2193 introduced and which
is in no release tag -- absent at v1.5.0b14 -- so no released version ever
emitted it. #2403 is no longer skipped as internal because it reworded an
existing bullet to name __proto_dest__ while nothing credited the
attribute's introduction.

Four claims are corrected against the source rather than carried over:
FTP_DATA shipped in pcapkit/protocols/application/ftp.py from 1.0.0, not
1.4.0 (class FTP_DATA(Raw) is there at v1.0.0); #2365's pre-fix fallback
read cmmd.value, so a .value-carrying object was accepted unchecked
rather than raising; #2399 left the dpkt adapter and the adapters'
ModuleNotFound raises alone, so it claims no universal prefix; and
#2397's old tail did name the version it got, so the entry quotes it and
gains the :issue:`2302` it was missing. #2370's "a Section Header Block
... still fails" sentence is dropped: #2369 settles the byte order first,
and an SHB built from raw octets with ctx=None now rebuilds byte-exact in
both byte orders.

CHANGELOG.md is regenerated with util/changelog_md.py.

Test: tests/project/ in full, 0 failures, including test_changelog_md.py's
in-step and supported-subset checks; util/changelog_md.py --check reports
the two files in step; the entry parses under docutils with no structural
warning.
JarryShaw added a commit that referenced this pull request Oct 28, 2026
#1103 whole-repo prose sweep over the maker-message wave (#2296, #2404, #2405,
#2407) and the __proto_dest__ registry refactor (#2392, #2403).

Docstrings corrected where the prose did not match the code:

* ``Protocol`` -> ``ProtocolBase`` in the ``register``/``register_protocol``
  cross-references (protocol.py, internet.py, link.py, transport.py, sctp.py,
  registry/protocols.py).
* ``Raises:`` entries for the ``bool`` port guard (#2287) in TCP, UDP and SCTP
  ``make``, and for HTTP/1's request-without-``uri`` guard.
* ``protochain`` documented on both sides of its narrowing to ``None``
  (protocol.py, misc/null.py, #2317), and ``__init__`` names the
  ``__own_make_keywords__`` exception to its keyword check.
* IP reassembly names the IPv6 ``M`` bit and which buffer an atomic fragment is
  isolated from (#2270); ``_check_code`` names ``register_protocol_code`` among
  its callers (#2186).
* HIP's shared lifetime helper says where the octet appears instead of counting
  the makers that carry it, and ``_make_opt_pad`` warns and makes a ``PadN``
  rather than raising as its reader does.

Before/after narration replaced with present tense, the pattern #1103's round 6
banned:

* the ``__proto_dest__`` prose in the registration and vendor tests, and the
  ``register_protocol_code`` key-check narration;
* the #2296 and #2406 maker-message module docstrings -- readers are exempt by
  design rather than "deliberately untouched", and the HTTP ``frame=None`` case
  is outside the guard rather than one the guard "has not widened to";
* the ``_NameLease`` rationale and the ``register_protocol`` name-collision
  note in registry/protocols.py, which described a fix and a redesign in the
  past tense;
* TCP's ``_make_mptcp_unknown`` length comment, which contrasted the current
  expression with "the former" one.

AST guard (``ast.dump`` via util/vendor_code_changed.py's ``code_of``, with
docstrings and bare string literals stripped) confirms all 16 touched files are
prose-only against e48062c. 129 tests pass (1 pre-existing skip) with 334
subtests across the four touched test modules, tests/test_docstring_contract.py,
tests/project/test_conventions_doc_claims.py,
tests/project/test_docs_issue_pr_roles_1103_unit.py and
tests/project/test_issue_refs_in_comments.py.
JarryShaw added a commit that referenced this pull request Oct 28, 2026
Problem: of the 60 pull requests merged in the #2312-#2407 range, only
#2334, #2336, #2337, #2340 and #2348 wrote a 1.5.0 changelog entry, and
#2398 and #2403 only reworded lines that were already there. Every other
user-visible change in the range -- wire-semantics fixes, maker guards,
reassembly behaviour, public-API and error-message changes -- went
unrecorded, so the entry no longer describes the release.

Fix: one entry per user-visible pull request, in each module section's
existing style and ordered by the issue it closes. Three pairs share a
bullet, since each is the direct follow-up or counterpart of the other:
#2393 with #2401, #2405 with #2407, and #2392 with #2403. The diff on the
entry file is purely additive.

Internal-only work is left out deliberately: dependency and action bumps
(#2387 to #2391), test-only and docs-prose passes (#2333, #2376, #2379,
#2380, #2402), the unreachable-branch removal (#2378), and the #: comment
marker the HIP Group and Packet crawlers now write (#2381). That last one
renders nothing either way: the marker lands inside the generated
_missing_ body, conf.py's exclude-members drops _missing_ from autodoc,
and a comment in a method body is not an attribute comment to begin with.

#2392 and #2403 are recorded together, under Added rather than Fixed, for
the declarations they introduce: __proto_key__ on each class owning a
__proto__ registry (#2392), __proto_dest__ on the enum registries and
Vendor.PROTO_DEST to generate it (#2403). The bullet names those classes
and registries rather than counting them, per the no-counted-numbers rule
for the unreleased entry. Both PRs added the autodoc entries, so both are
rendered public attributes. #2392's rejection-message
change is deliberately not recorded as a fix: the bare "code must be ..."
text it prefixed came from _check_code, which #2193 introduced and which
is in no release tag -- absent at v1.5.0b14 -- so no released version ever
emitted it. #2403 is no longer skipped as internal because it reworded an
existing bullet to name __proto_dest__ while nothing credited the
attribute's introduction.

Four claims are corrected against the source rather than carried over:
FTP_DATA shipped in pcapkit/protocols/application/ftp.py from 1.0.0, not
1.4.0 (class FTP_DATA(Raw) is there at v1.0.0); #2365's pre-fix fallback
read cmmd.value, so a .value-carrying object was accepted unchecked
rather than raising; #2399 left the dpkt adapter and the adapters'
ModuleNotFound raises alone, so it claims no universal prefix; and
#2397's old tail did name the version it got, so the entry quotes it and
gains the :issue:`2302` it was missing. #2370's "a Section Header Block
... still fails" sentence is dropped: #2369 settles the byte order first,
and an SHB built from raw octets with ctx=None now rebuilds byte-exact in
both byte orders.

CHANGELOG.md is regenerated with util/changelog_md.py.

Test: tests/project/ in full, 0 failures, including test_changelog_md.py's
in-step and supported-subset checks; util/changelog_md.py --check reports
the two files in step; the entry parses under docutils with no structural
warning.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

const Regenerated IANA or vendor constant tables; members keep their numeric values refactor Restructuring for its own sake — neither a fix nor a new capability (refactor: prefix)

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant