Skip to content

fix(ipx): order Socket._missing_ range branches narrowest-first - #847

Merged
JarryShaw merged 1 commit into
mainfrom
fix/841-ipx-socket-range-order
Sep 27, 2026
Merged

JarryShaw merged 1 commit into
mainfrom
fix/841-ipx-socket-range-order

Conversation

@JarryShaw

@JarryShaw JarryShaw commented Sep 27, 2026 •

Copy link
Copy Markdown
Owner

Please follow the guide below

What is the purpose of your pull request?

  • fix — corrects a defect

Description of your pull request and other information

Closes #841.

Socket._missing_ tested its five range branches in the order the archived rows appeared, and three
of them were strict subsets of a range tested earlier, so they never fired:
(0x0020, 0x003F) after (0x0001, 0x0BB8), and both (0x4000, 0x4FFF) and (0x8000, 0xFFFF)
after (0x0BB9, 0xFFFF). Eight sampled sockets therefore resolved under the wrong range's name.

The fix is in the generator — RANGES in pcapkit/vendor/ipx/socket.py now lists each subset
range ahead of the range containing it — and pcapkit/const/ipx/socket.py changes only as the
regenerated consequence. Verified byte-identical: regenerating from this branch reproduces the
committed const file exactly (md5 739fdbf69572fbf982f8e25cfb31f679).

This is a visible name change, which is why it carries breaking — and the scale is large.
36891 of the 65521 _missing_-resolved values (56.3%) change name. An earlier draft of this
description said "eight sampled sockets", which was the sampled count in the tests and badly
understated the blast radius; the cross-review caught it and the full-space figure is re-derived here:

previously now values
Registered by Xerox Experimental 32
Dynamically Assigned Dynamically Assigned Socket Numbers 4095
Dynamically Assigned Statically Assigned Socket Numbers 32764

32 + 4095 + 32764 = 36891. The three deductions from the full spans are the defined members inside
them — 0x4003, and 0x8060/0x9091/0x9092/0x9093 — which never reach _missing_. No defined
member changes
, all 15 are identical, every value still resolves, and int(member) == value holds
throughout. Every one of the 36891 moves from a wide catch-all to the narrower archived row that
actually covers it.

The prior tests pinned the bug as intended behaviour — EXPECTED_MISSING_NAMES carried
# masks 'Experimental' comments and a docstring calling the shadowing "preserved scrape behaviour
rather than a defect". Those assertions are corrected here, not dropped, and a new
test_previously_shadowed_ranges_are_reachable pins all three ranges.

Two source contradictions this exposes, flagged rather than buried.

  1. The archived (0x4000, 0x4FFF) upper bound contradicts the source prose ("between 0x4000 and
    0x7FFF are dynamic sockets"). Nothing in 0x5000–0x7FFF changes in this PR — it reads
    Dynamically Assigned before and after. What changes is that the bound is now load-bearing:
    while the branch was dead the bound had no observable effect, and widening it to 0x7FFF would
    now move 12288 values.
  2. The archived table is also self-contradictory over 0x8000–0xFFFF: (0x0BB9, 0xFFFF) "Dynamically Assigned" and (0x8000, 0xFFFF) "Statically Assigned Socket Numbers" cannot both
    hold. Narrowest-first decides it in favour of the specific row, which is right, but it is a second
    conflict being settled as a side effect.

Both transcriptions are left faithful to the archived table rather than silently widened. Worth their
own issue if the prose should win.

Verification, re-run by me on this rebased branch rather than taken from the worker's report:

  • coverage run -m pytest tests/vendor/test_ipx_socket_unit.py tests/const/ → 109 passed, 39477 subtests passed
  • the new tests against unfixed main → 12 failed, including all three shadowed-range subtests
  • Socket(0x0000) still resolves to Socket.Unspecified — it is a defined member and never reaches _missing_

Out of scope: the range branches still mint descriptive names via extend_enum; removing that is
#775's tier 2.

- pcapkit/vendor/ipx/socket.py: RANGES listed the wide "Registered by
  Xerox" and "Dynamically Assigned" rows before the narrower ranges they
  fully contain, so Experimental (0x0020-0x003F), Dynamically Assigned
  Socket Numbers (0x4000-0x4FFF) and Statically Assigned Socket Numbers
  (0x8000-0xFFFF) could never be reached in the generated `_missing_`.
  Reorder each subset range ahead of the wider range that masks it.
- pcapkit/const/ipx/socket.py: regenerated from the fixed vendor module;
  only the branch order changes.
- tests/vendor/test_ipx_socket_unit.py: update EXPECTED_RANGES and
  EXPECTED_MISSING_NAMES, which pinned the old (shadowed) behaviour, and
  add test_previously_shadowed_ranges_are_reachable pinning 0x0030,
  0x4080 and 0x8100 to their now-correct names.

Verified `python -m coverage run -m pytest tests/vendor/test_ipx_socket_unit.py`
passes (10 passed, 19 subtests), and Socket(0x0000) still resolves as
Unspecified. Closes #841.
@JarryShaw JarryShaw added fix Pull requests that fix a defect (fix: subject prefix) const Regenerated IANA or vendor constant tables; members keep their numeric values breaking Breaks public-facing behaviour or API (apply alongside the type label) review: pending No verdict for the current head - never reviewed, or the head moved since the last one labels Sep 27, 2026
@JarryShaw

Copy link
Copy Markdown
Owner Author

GOOD TO GO on 072c9ddac — cross-review (opus, a different model from the sonnet author) found no
code defect, and CI is 27 ✅ / 0 ❌ / 3 skipped / 0 incomplete.

It did catch one thing worth more than the verdict: my description understated the blast radius by
three orders of magnitude.
I wrote "eight sampled sockets"; the true figure is 36891 of the 65521
_missing_-resolved values (56.3%)
. I re-derived it rather than relaying it — 32 Experimental

  • 4095 Dynamically Assigned Socket Numbers + 32764 Statically Assigned Socket Numbers, the
    deductions being the defined members inside those spans (0x4003, 0x8060, 0x9091–0x9093), which
    never reach _missing_. Description corrected above. breaking is more clearly warranted than the
    body implied, not less.

What the review verified independently, each derived twice:

  • three unreachable branches, by pairwise containment over all 20 ordered pairs and by a live
    65536-value sweep of the pre-fix tree, where only two of five labels ever appear
  • no new shadowing — zero i<j containments in the new order, and each range checked against the
    union of all earlier ranges, so no branch is dead even to a combined mask
  • 0 values raise in either tree; 0 defined members change; int(member) == value throughout
  • const file byte-reproducible from the generator in both trees, md5 739fdbf69572fbf982f8e25cfb31f679
  • the test change strengthens: 9 → 10 methods, 12 → 14 assertions, EXPECTED_MISSING_NAMES keeps
    all 14 keys with values corrected, nothing loosened; against unfixed main under plain unittest
    (not pytest, to defeat the subtests undercount) → Ran 10 tests, FAILED (failures=12)
  • scope clean: exactly the three owned files, one commit

It also surfaced a second source contradiction the PR had not flagged — (0x0BB9, 0xFFFF) "Dynamically Assigned" and (0x8000, 0xFFFF) "Statically Assigned Socket Numbers" cannot both hold.
Narrowest-first settles it in favour of the specific row, which is right, but it is a conflict being
decided as a side effect. Added to the description alongside the 0x4FFF/0x7FFF one.

Ready for you to merge.

@JarryShaw JarryShaw added review: good-to-go Cross-review at the current head says ready; CI state is separate and removed review: pending No verdict for the current head - never reviewed, or the head moved since the last one labels Sep 27, 2026
@JarryShaw

Copy link
Copy Markdown
Owner Author

Should experimental and dynamically assigned actually be considered as same category of unassigned/reserved? Meaning we don't mint them to the class with extend_enum.

@JarryShaw

Copy link
Copy Markdown
Owner Author

Recorded, verbatim: "Should experimental and dynamically assigned actually be considered as same
category of unassigned/reserved? Meaning we don't mint them to the class with extend_enum."

Yes for experimental, and #838 already set that precedent — but "dynamically assigned" is a different
thing and I would not fold it in.
Measured on origin/main @ 30bca999c:

#838 already routes four description kinds through _unregistered_member rather than minting:

 43  _unregistered_member(value, 'Unassigned')
  4  _unregistered_member(value, 'Reserved_for_Private_Use')
  1  _unregistered_member(value, 'Reserved')
  1  _unregistered_member(value, 'Deprecated')

So the category is already wider than "Unassigned" — Reserved_for_Private_Use and Deprecated
are in it. What still mints, and is the same kind of thing, is the obvious next batch:

  3  Reserved_for_Experimental_Use      2  Reserved_for_Testing_Purposes_Only
  2  Reserved_for_Private_Use           1  Reserved for experimental use
 12  Reserved                         129  Unassigned

All of those say "the registry defines no specific meaning at this value", which is exactly
_unregistered_member's contract. Recommend folding them in.

Dynamically Assigned / Statically Assigned / Registered by Xerox are not that. They say who
assigns or who registered — a positive statement about the value, not an absence of one. ipx/socket
is also the only registry shaped this way: it is the sole vendor module with a module-level RANGES
table, and the only one whose range descriptions carry no Unassigned at all. Folding them in would
discard real information the archived table provides.

This does not change #847, which is why I am not holding it. Whether the range branches mint or
call _unregistered_member, they are still tested in order and the first match still decides which
description
the value carries. The reordering is required either way; only the 36891 differences
change from member names to unregistered-member descriptions. #847 stays review: good-to-go.

Where it does land is #775 tier 2 — this is the same "stop minting" work, so I have added it there
rather than opening a third issue. Tell me if you would rather it were separate.

@JarryShaw

Copy link
Copy Markdown
Owner Author

I'd argue that dynamically/statically assigned are the same level of *unspecified^ values tho. They should and will have concrete names when being assigned right? If that so, the criteria of (un)minting should be - is this considered as the final concrete assigned name (mint), or just a notation for the readers (unmint)?

@JarryShaw

Copy link
Copy Markdown
Owner Author

Recorded, verbatim: "I'd argue that dynamically/statically assigned are the same level of unspecified
values tho. They should and will have concrete names when being assigned right? If that so, the criteria
of (un)minting should be - is this considered as the final concrete assigned name (mint), or just a
notation for the readers (unmint)?"

Conceded — your criterion is better than the one I proposed, and it overturns my own recommendation.
I split on "absence of meaning vs positive statement", which put Dynamically Assigned and Registered by Xerox on the mint side. "Final concrete assigned name vs notation for the reader" is the right test,
and by it both are notation: the socket gets its real name when something actually assigns it.

Applied to every still-minting description in _missing_ on origin/main @ 30bca999c, AST-counted:

Notation → unmint. Unassigned 133 sites / 70 files, plus Unassigned_%04x/_0x%04x/_0b/
_0x%08x 6, Reserved 7, Reserved_%08x 5, Reserved_for_Experimental_Use 3,
Reserved_for_Private_Use 2, Reserved_for_Testing_Purposes_Only 2, Reserved for experimental use 1,
DEC_Unassigned 3, Unknown 2, opt_unknown 1, Unassigned_available_for_{success,reject}_codes 2 —
and now, per your ruling, ipx/socket's Experimental, Dynamically Assigned, Dynamically Assigned Socket Numbers, Statically Assigned Socket Numbers and Registered by Xerox, 1 each.

CODE_* is notation too — 9 sites in ftp/return_code.py and http/status_code.py, and the HTTP
ones make it explicit by passing 'Unassigned' as the member's own description:
extend_enum(cls, 'CODE_%d' % value, value, 'Unassigned').

Mint — and this is the group I did not expect. pcapkit/const/reg/ethertype.py mints roughly 50
company names
: Xyplex 2, Datability 2, Qualcomm 2, Charles_River_Data_System 2, then
Motorola, Novell_Inc, Kinetics, Wellfleet_Communications, Landmark_Graphics_Corp … 1 each, plus
IEEE802_3_Length_Field and Berkeley_Trailer_encap_IP.

One judgement call I will not make for you, because the criterion is genuinely thin there.
Xyplex_0x0888 and Registered by Xerox_0x0004 both name a company. I read the ethertype ones as mint —
IEEE's record for that specific value — and the ipx one as unmint, since it is a statement about the
range, not about the socket. But that is a reading, not a measurement, and if you see them the same then
~50 more sites move. Your call.

Nothing here changes #847: minted or not, the first matching range still decides the description, so the
ordering fix stands. The test-name coupling I flagged on #841 now covers all five of its ranges rather
than just Experimental. Carried into #775 tier 2.

@JarryShaw

Copy link
Copy Markdown
Owner Author

Company names is actually a strong enough concrete name I think? Their protocols are proprietary and may not actually expose their own names - thus company names become the "name" for them.

@JarryShaw

Copy link
Copy Markdown
Owner Author

Recorded, verbatim: "Company names is actually a strong enough concrete name I think? Their protocols
are proprietary and may not actually expose their own names - thus company names become the 'name' for
them."

That settles the one call I explicitly left to you, and in the direction I had read it. So under your
criterion the split is now complete, with no judgement left hanging:

  • Mint — reg/ethertype.py's ~50 company names (Xyplex, Motorola, Novell_Inc, Qualcomm,
    Landmark_Graphics_Corp, …), plus IEEE802_3_Length_Field and Berkeley_Trailer_encap_IP. Your
    reasoning is the stronger one: a proprietary protocol may never publish a name of its own, so the
    company is the assignment.
  • Unmint — everything that is notation: Unassigned 133 sites / 70 files and its four format
    variants 6, Reserved 7, Reserved_%08x 5, the three Reserved_for_* kinds 8, DEC_Unassigned 3,
    Unknown 2, opt_unknown 1, both Unassigned_available_for_* 2, CODE_* 9 — and ipx/socket's five,
    including Registered by Xerox, which is a statement about the range rather than the socket.

The distinction that makes both rulings consistent: Xyplex_0x0888 is IEEE's record for that value;
Registered by Xerox_0x0004 only says the value falls inside a range Xerox registered. Recorded on
#775 tier 2, which now has the full classification rather than a pending question.

@JarryShaw

Copy link
Copy Markdown
Owner Author

So are we making updates to this PR or we will deal with these in a separate one? Wondering if I should merge now.

@JarryShaw

Copy link
Copy Markdown
Owner Author

Recorded, verbatim: "So are we making updates to this PR or we will deal with these in a separate one?
Wondering if I should merge now."

Merge now. No updates to this PR. Three reasons, in order of weight:

  1. The unminting change would rewrite this PR's own tests, not extend them. Folding all five ranges into
    _unregistered_member turns Socket(0x0030) from a minted member named Experimental_0x0030 into an
    unregistered member carrying that description — so test_previously_shadowed_ranges_are_reachable and the
    8 pinned entries in EXPECTED_MISSING_NAMES would all change. Doing it here would mean landing a fix and
    immediately rewriting its evidence in the same breath.
  2. The ordering fix is required either way. Minted or not, _missing_ still tests the ranges in sequence
    and the first match still decides which description a value gets. Nothing about the unminting makes this
    PR's reordering unnecessary or wrong.
  3. It is already scoped where it belongs. The full mint/unmint classification from your criterion —
    including the ~50 ethertype company names on the mint side and CODE_* plus ipx/socket's five on the
    unmint side — is recorded against Registries mint a permanent member for every unrecognised value: 1,169 extend_enum sites across 113 registries #775 tier 2, whose worker is holding it now. Pulling it forward into
    fix(ipx): order Socket._missing_ range branches narrowest-first #847 would split that work across two PRs.

State of this PR as it stands: head 072c9ddac, 27 ✅ / 0 ❌ / 3 skipped / 0 incomplete, review: good-to-go from an opus cross-review that independently re-derived the three-unreachable-branches finding
twice, confirmed no new shadowing across all 20 ordered pairs, and swept all 65536 values against both trees.
One commit, exactly its three owned files.

The one thing that is yours rather than mine here: the description now states the real blast radius —
36891 of 65521 _missing_-resolved values (56.3%) change name — which I had originally understated as
"eight sampled sockets". If that scale changes your mind about merging it as breaking rather than sequencing
it behind the unminting, say so and I will hold.

@JarryShaw
JarryShaw merged commit c5f7478 into main Sep 27, 2026
31 checks passed
@JarryShaw
JarryShaw deleted the fix/841-ipx-socket-range-order branch September 27, 2026 13:28
@JarryShaw JarryShaw removed the review: good-to-go Cross-review at the current head says ready; CI state is separate label Sep 27, 2026
JarryShaw added a commit that referenced this pull request Sep 27, 2026
pcapkit.const.ipx.socket.Socket's _missing_ tested its five archived
range branches in table order, and three were strict subsets of a range
tested earlier, so they never fired. Fixed in the generator,
pcapkit/vendor/ipx/socket.py, which now lists each subset range ahead of
the range containing it.

Marked breaking: 36891 of the 65521 _missing_-resolved values (56.3%)
change name, entirely a shift in which archived row's name a
previously-shadowed value receives -- no defined member changes and every
value still resolves. The prior tests had pinned the shadowing as
intended behaviour; those assertions are corrected here rather than
dropped.
JarryShaw added a commit that referenced this pull request Sep 27, 2026
Adds util/pyshark_encap_map.py, a generator that regenerates
ENCAP_TYPE_TO_LINKTYPE (152 entries) and FILTER_NAME_TO_LINKTYPE (58) in
place inside pcapkit/toolkit/pyshark.py, so the two tables #850 hand-built
stop being hand-maintained. Guards against its own worst failure mode: a
naive LinkType(dlt) lookup cannot detect an unmapped DLT, because
_missing_ mints a placeholder rather than raising, so the generator
snapshots every known value before any lookup.

The real-tshark sweep is gated on a new HAS_WIRESHARK flag and is
version-pinned -- editcap -T accepts 226 encapsulations on Wireshark
4.6.9, 224 on 4.2.2 (CI's Ubuntu noble) -- so the count assertions run
only under the measured version. One line of pyshark.py itself changes as
a result: the IPMB_LINUX table entry becomes I2C_LINUX, the canonical
name #848 gave value 209.

util/changelog_md.py regenerated CHANGELOG.md for all seven entries added
across this and the six preceding commits (#838, #846, #847, #848, #849,
#850, #853); `--check` exit 0.
JarryShaw added a commit that referenced this pull request Sep 27, 2026
#846 and #850

- #838's "the 21 whose vendor crawler leaves Vendor.process() unmodified"
  measures 22, not 21 -- pcapkit.const.hip.transport.Transport also has an
  unmodified process(), but its FLAG-bound range has no unassigned gap, so
  its _missing_ carries no bounded-range extend_enum branch to fix. The
  real discriminator is that branch, not the process() override; reworded,
  and the "other 84" split into the 83 that do override process() and the
  one that doesn't but has nothing to fix either. Re-derived independently
  against 5e25db2^..5e25db2 (not main, which would fold in #847's own
  edit to ipx/socket.py): 22 registries have no process() override, 21 of
  them have the bounded-range branch, matching
  tests/const/test_const_enum_no_mint.py's own REGISTRIES_WITH_UNASSIGNED_RANGES
  (21 entries) vs ALL_REGISTRIES (22, +hip.transport, with a NOTE explaining
  the exclusion).

- #846's "Only tests/integration/test_engine_runtime.py and
  test_engine_parity.py change" is false -- 30bca99's own numstat also
  touches .github/workflows/unit-tests.yml (17+/2-). Qualified to "only
  these two test files change".

- #850 gets the breaking marker: its own prose already says the fallback
  is gone and an unrecognised encapsulation or filter name now raises
  MissingKeyError instead of substituting a plausible DLT -- the same
  shape as the two existing markers at AppType.get (1.5.0.rst:2456) and
  the four .get()-backed enum fields (1.5.0.rst:2720). Restructured to
  lead with the marker and the subject, matching their wording and
  placement; the later restatement of the same fact is dropped.

None of these are code or test changes -- prose only, matching the
cross-review's own framing. #848 stays unmarked (its own "Not breaking"
paragraph holds); #838, #849 and #853 stay unmarked per explicit
instruction not to add markers beyond what was asked.
JarryShaw added a commit that referenced this pull request Sep 27, 2026
…ng convention

Both are design rulings a maintainer or automated contributor cannot derive from the
code, and both were settled in issue threads that are easy to lose.

- the mint vs unmint test for `_missing_`: a final concrete assigned name mints, a
  notation for the readers does not (#775, #847), with the ethertype company names
  explained as the case that looks like an exception and is not
- the `<SENTINEL>Type` class-naming rule, why a dedicated class beats a bare
  `object()` (a readable repr in signatures and tracebacks, not safety), and why the
  three sentinels deliberately differ on `__bool__` and the copy hooks
- where the registry protocol lives, and why the bespoke registries are not on it yet

Verified with a real Sphinx build rather than bare docutils -- `:mod:`, `:meth:` and
`.. seealso::` are Sphinx constructs that plain docutils reports as errors.
JarryShaw added a commit that referenced this pull request Sep 27, 2026
…registries (#775)

- classify every one of the 89 `_missing_` bodies still calling `extend_enum`
  against the owner's ruling on #775/#847: a final concrete assigned name
  mints, a notation for the reader (Unassigned/Reserved/Deprecated/etc.)
  unmints
- convert 82 registries wholly and two more (`EtherType`, `Socket`) partially,
  172 branches total, from `extend_enum` to `_unregistered_member`, in both
  the vendor crawler and the generated const file, following #838's/#858's
  precedent; proved a 5-file sample (Form-A and Form-B crawlers, both mixed
  registries) regenerates byte-identically
- leave 89-82=7 untouched: `CGAType`'s mint is not an IANA-style range at all,
  and 6 files sit on classes without `EnumRegistry` yet (`AppType` and
  friends), tracked separately by #860 pending #859
- extend `tests/const/test_const_enum_no_mint.py` with the ruling-derived
  registry lists and behavioural/source coverage for all 82+2, correct its
  stale "~92 still mint" docstring to the measured 89, and fix collateral
  breakage in three sibling test files and `tests/vendor/test_ipx_socket_
  unit.py` that pinned the pre-ruling mint behaviour

- fix the last two collateral pins the ruling invalidates, in files the first
  pass missed and CI caught: `tests/corekit/test_fields_numbers_unassigned_
  enum.py` expected `BlockType(0x0bad0bad).name == 'Reserved_0bad0bad'`, now
  `Reserved` with the value asserted explicitly since the name no longer
  carries it; and `tests/protocols/misc/test_pcapng_unit.py` read
  `FilterType.Unassigned_0` by attribute, a member that existed only because
  of the import-time mint at `pcapkit/protocols/misc/pcapng.py:4593` which
  this change removes

Build: plain `unittest` on tests/const (179), tests/vendor (86),
tests/corekit/test_fields_numbers_unassigned_enum.py (11) and
tests/protocols/misc/test_pcapng_unit.py (92 + 1 skipped) all green; both
newly-fixed files fail with their const file reverted to main.
JarryShaw added a commit that referenced this pull request Sep 27, 2026
…registries (#775)

- classify every one of the 89 `_missing_` bodies still calling `extend_enum`
  against the owner's ruling on #775/#847: a final concrete assigned name
  mints, a notation for the reader (Unassigned/Reserved/Deprecated/etc.)
  unmints
- convert 82 registries wholly and two more (`EtherType`, `Socket`) partially,
  172 branches total, from `extend_enum` to `_unregistered_member`, in both
  the vendor crawler and the generated const file, following #838's/#858's
  precedent; proved a 5-file sample (Form-A and Form-B crawlers, both mixed
  registries) regenerates byte-identically
- leave 89-82=7 untouched: `CGAType`'s mint is not an IANA-style range at all,
  and 6 files sit on classes without `EnumRegistry` yet (`AppType` and
  friends), tracked separately by #860 pending #859
- extend `tests/const/test_const_enum_no_mint.py` with the ruling-derived
  registry lists and behavioural/source coverage for all 82+2, correct its
  stale "~92 still mint" docstring to the measured 89, and fix collateral
  breakage in three sibling test files and `tests/vendor/test_ipx_socket_
  unit.py` that pinned the pre-ruling mint behaviour

- fix the last two collateral pins the ruling invalidates, in files the first
  pass missed and CI caught: `tests/corekit/test_fields_numbers_unassigned_
  enum.py` expected `BlockType(0x0bad0bad).name == 'Reserved_0bad0bad'`, now
  `Reserved` with the value asserted explicitly since the name no longer
  carries it; and `tests/protocols/misc/test_pcapng_unit.py` read
  `FilterType.Unassigned_0` by attribute, a member that existed only because
  of the import-time mint at `pcapkit/protocols/misc/pcapng.py:4593` which
  this change removes

Build: plain `unittest` on tests/const (179), tests/vendor (86),
tests/corekit/test_fields_numbers_unassigned_enum.py (11) and
tests/protocols/misc/test_pcapng_unit.py (92 + 1 skipped) all green; both
newly-fixed files fail with their const file reverted to main.
JarryShaw added a commit that referenced this pull request Sep 28, 2026
…ed value (#878)

Converts the last 53 minting `extend_enum` sites in the const registries,
closing out issue #775: EtherType's 52 range branches and Socket's one
("Registered by Xerox"), the two registries the original #775/#847 ruling
held out because their names were real attributed protocols rather than
placeholder status words.

- `pcapkit/vendor/reg/ethertype.py` and `pcapkit/vendor/ipx/socket.py`:
  the `process()` else-branch that used to render
  `extend_enum(cls, name, value)` now renders
  `cls._unregistered_member(value, name)` instead, keeping every branch's
  existing hex-suffixed name argument unchanged -- this is about not
  registering, not about renaming anything.
- `pcapkit/const/reg/ethertype.py` and `pcapkit/const/ipx/socket.py`
  regenerated to match: Socket regenerated byte-for-byte offline (its
  `LINK` is `None`, so no network call is involved); EtherType hand-applied
  with the identical mechanical substitution, verified against the
  crawler's own `process()` fed the real IANA CSV fixture already
  committed for issue #862.
- `pcapkit/corekit/enum.py`: `EnumRegistry.get()`'s docstring no longer
  claims three registries still mint directly; only `CGAType` does now.
- `tests/const/test_const_enum_no_mint.py`: the two "mixed registry" test
  classes are retitled in place to prove the formerly-kept probe
  (`Xyplex`, `Registered by Xerox`) no longer mints, and a new, scoped
  `HEX_SUFFIXED_NAME_EXEMPT_PATHS` exemption lets the manufactured-name
  sweep tolerate the deliberately-preserved hex suffix on just these two
  files, without weakening `is_manufactured()` itself.
- `tests/const/test_const_ethertype_862_unit.py`,
  `tests/const/test_const_registry_protocol.py` and
  `tests/vendor/test_ipx_socket_unit.py`: three call sites that asserted
  the old minting behaviour flipped to assert non-minting instead.

Built and verified offline (no live crawl): AST sweep over pcapkit/const/
now finds exactly 1 remaining minting site (CGAType, deliberately
untouched); tests/const/test_const_enum_lookup.py (13/13) and
tests/vendor/test_vendor_missing_body_unit.py (6/6) pass with 0
failures/errors.

Refs #775
JarryShaw added a commit that referenced this pull request Sep 28, 2026
pcapkit.const.ipx.socket.Socket's _missing_ tested its five archived
range branches in table order, and three were strict subsets of a range
tested earlier, so they never fired. Fixed in the generator,
pcapkit/vendor/ipx/socket.py, which now lists each subset range ahead of
the range containing it.

Marked breaking: 36891 of the 65521 _missing_-resolved values (56.3%)
change name, entirely a shift in which archived row's name a
previously-shadowed value receives -- no defined member changes and every
value still resolves. The prior tests had pinned the shadowing as
intended behaviour; those assertions are corrected here rather than
dropped.
JarryShaw added a commit that referenced this pull request Sep 28, 2026
Adds util/pyshark_encap_map.py, a generator that regenerates
ENCAP_TYPE_TO_LINKTYPE (152 entries) and FILTER_NAME_TO_LINKTYPE (58) in
place inside pcapkit/toolkit/pyshark.py, so the two tables #850 hand-built
stop being hand-maintained. Guards against its own worst failure mode: a
naive LinkType(dlt) lookup cannot detect an unmapped DLT, because
_missing_ mints a placeholder rather than raising, so the generator
snapshots every known value before any lookup.

The real-tshark sweep is gated on a new HAS_WIRESHARK flag and is
version-pinned -- editcap -T accepts 226 encapsulations on Wireshark
4.6.9, 224 on 4.2.2 (CI's Ubuntu noble) -- so the count assertions run
only under the measured version. One line of pyshark.py itself changes as
a result: the IPMB_LINUX table entry becomes I2C_LINUX, the canonical
name #848 gave value 209.

util/changelog_md.py regenerated CHANGELOG.md for all seven entries added
across this and the six preceding commits (#838, #846, #847, #848, #849,
#850, #853); `--check` exit 0.
JarryShaw added a commit that referenced this pull request Sep 28, 2026
#846 and #850

- #838's "the 21 whose vendor crawler leaves Vendor.process() unmodified"
  measures 22, not 21 -- pcapkit.const.hip.transport.Transport also has an
  unmodified process(), but its FLAG-bound range has no unassigned gap, so
  its _missing_ carries no bounded-range extend_enum branch to fix. The
  real discriminator is that branch, not the process() override; reworded,
  and the "other 84" split into the 83 that do override process() and the
  one that doesn't but has nothing to fix either. Re-derived independently
  against 5e25db2^..5e25db2 (not main, which would fold in #847's own
  edit to ipx/socket.py): 22 registries have no process() override, 21 of
  them have the bounded-range branch, matching
  tests/const/test_const_enum_no_mint.py's own REGISTRIES_WITH_UNASSIGNED_RANGES
  (21 entries) vs ALL_REGISTRIES (22, +hip.transport, with a NOTE explaining
  the exclusion).

- #846's "Only tests/integration/test_engine_runtime.py and
  test_engine_parity.py change" is false -- 30bca99's own numstat also
  touches .github/workflows/unit-tests.yml (17+/2-). Qualified to "only
  these two test files change".

- #850 gets the breaking marker: its own prose already says the fallback
  is gone and an unrecognised encapsulation or filter name now raises
  MissingKeyError instead of substituting a plausible DLT -- the same
  shape as the two existing markers at AppType.get (1.5.0.rst:2456) and
  the four .get()-backed enum fields (1.5.0.rst:2720). Restructured to
  lead with the marker and the subject, matching their wording and
  placement; the later restatement of the same fact is dropped.

None of these are code or test changes -- prose only, matching the
cross-review's own framing. #848 stays unmarked (its own "Not breaking"
paragraph holds); #838, #849 and #853 stay unmarked per explicit
instruction not to add markers beyond what was asked.
JarryShaw added a commit that referenced this pull request Oct 1, 2026
…ision (#719)

Accuracy fixes, each re-derived against the code:

- mint-criterion.rst presented `EtherType`'s company names and `Socket`'s
  `Registered by Xerox` as the worked *mint* examples. #878 converted both to
  `_unregistered_member`; `CGAType` is now the only `_missing_` that mints, so
  the criterion decides the unregistered member's *name*, not whether it
  registers.
- Its `ast` snippet matched only `ast.Name` callees, so it reported 1 MINT and
  0 UNMINT; `_unregistered_member` is called on `cls`. Matches attributes now.
- "Every registry defines `_missing_`" -> 121 of 127, naming the six without one.
- registry-protocol.rst: `__new__` exemption said "a handful ... tracked in
  #860"; it is six named classes and #860 closed with all 127 on the base.
- The 6 mh/ngap helpers are not all numeric: `PDUKind` is `str`, and it was
  listed in two rows at once.
- `TCP`/`UDP`/`SCTP`/`DCCP` member *names* come from the service-name column;
  the values are composites.
- process.rst: 9 sections, 8 of them module-level; `pcapkit.interface` has none.
- sentinel-convention.rst: `NO_VALUE` also lacks `__copy__`/`__deepcopy__`/
  `__reduce__`; the quoted `AbsentType` excerpt did not support the privacy
  claim it was cited for.
- Two `/issues/` links pointed at pull requests (#847, #913).

Concision: dropped timed context (the page's former title, the two-pass #877
history, the pre-#937 casing narrative, the pre-restructure changelog shape) and
fixed a duplicated clause. Added two Mermaid flows for `_missing_` and for
`get`'s dispatch, modelled on workflows.rst:102.

Build: docutils parse unchanged from base; tests/project/test_conventions_doc_claims.py
and the seven other suites reading these pages 111 passed, 1 skipped, 241 subtests.
JarryShaw added a commit that referenced this pull request Oct 2, 2026
#719

Swept tests/ for owner-ruling quotes attributed to the wrong GitHub
thread, the same defect class #719 fixed under pcapkit/. Confirmed each
by grepping the quote's distinctive text against the cited thread's
body/comments; a hit elsewhere is a re-quote or a different thread's
own words, not the source.

- test_sentinel_exports_unit.py: the already-reported #937->#719 fix
  for AbsentType's privacy ruling.
- test_enum_lookup_reparent_930_unit.py (4 sites) and test_mh_unit.py:
  "I prefer (2) directly" and the question that drew it are in pull
  request #940's thread, not issue #935 -- #935 only carries the first
  ruling ("I lean on 1").
- test_vendor_snapshot_restore_unit.py: the contextlib/atomic-write
  ruling is in pull request #873's thread; issue #872 has zero
  comments.
- test_vendor_reg_apptype_generator_unit.py (2 sites): the "undefined
  direct uses 0" ruling is in pull request #874's thread, not issue
  #860 or #770.
- test_const_enum_no_mint.py (2 sites): the mint/unmint criterion was
  settled on pull request #847 and confirmed on #775 -- the reverse of
  what the text said, per #861's own description of the same ruling;
  and "Q1 - bare it is." is pull request #838's thread, not #775's.

One occurrence left unresolved rather than guessed at: the "Preserve
each branch's existing name argument..." quote (4 sites in
test_const_enum_no_mint.py, attributed to "#775's final round") does
not appear verbatim in #775, #847, or #878 (the implementing PR) by
body, comments, review comments, or commit message -- only a
paraphrase in #878's own PR description/commit message, which is the
author's prose rather than a quoted ruling. Flagged for the owner
rather than fixed.

tests/corekit/, tests/vendor/, tests/const/ pass (400/16, 118, 299
respectively, pcapkit.__file__ confirmed inside this worktree);
tests/protocols/internet/test_mh_unit.py passes standalone (52/0) --
the full directory has 5 unrelated pre-existing failures from
ungenerated examples/captures/ fixtures, untouched by this change.

Refs #719
JarryShaw added a commit that referenced this pull request Oct 2, 2026
…719)

Per #719's citation ruling (de-quote, never reproduce a verbatim quote that
may have come from outside GitHub):

- test_const_enum_no_mint.py (4 sites): a quotation attributed to "the
  owner's ruling, verbatim" never appears in #775, #847, #861 or #878 (or
  anywhere in the repo's comment corpus). Replaced with a paraphrase
  attributed to PR #878's own body, which carries the real design note in
  different words.
- test_sentinel_exports_unit.py / test_const_registry_protocol.py: a quote
  attributed to #911 silently dropped half of what the owner wrote on #719
  and swapped `__all__` for "users". Replaced with a paraphrase naming #719
  as where it was settled and #911 as the issue that carried it out.
- test_const_enum_no_mint.py / test_const_enum_builtin_parity.py (4 sites):
  a "verbatim" quote of #860 silently corrected the owner's typo ("entires"
  -> "entries"). Paraphrased, which drops the question of reproducing or
  flagging the typo.
- test_enum_lookup_reparent_930_unit.py: "the owner's final ruling there"
  had #935 as its nearest antecedent instead of #940; named #940 explicitly
  and paraphrased the adjacent quote.

Verified: ast.parse and reST markup pairing clean on every touched file;
tests/const (299 tests) and the targeted pytest sweep of all touched files
(261 passed, 2013 subtests) are green. tests/corekit's full discover run
shows 5 pre-existing failures in test_sentinel_exports_unit.py, confirmed
identical on the unedited originals -- a cross-file test-order dependency
unrelated to this change.
JarryShaw added a commit that referenced this pull request Oct 2, 2026
… them, per #719

tests/ is exempt from the issue-citation rule (documentation.rst, ruled on
#719): the fact cited lives in the pull request, not the issue.

- PR #836 restored for the TransportProtocol-extension refusal, the
  |-composite decoding retirement, and the stale-comment deletion; the
  rulings are not on #808 at all.
- PR #783 for the f-string convention; PR #847 for the mint criterion.
- The de-quotation stands: wording stays as statements, no quotation marks.
JarryShaw added a commit that referenced this pull request Oct 2, 2026
…quest (#719) (#982)

* docs(pcapkit,ci): cite the issue a defect belongs to, not the pull request (#719)

Per the owner's ruling on #719, replace every reference to a pull-request
number in pcapkit/** and .github/workflows/** comments and docstrings with
the issue it closed, or a description where no issue covers it.

- 92 real PR citations in pcapkit/ (93 was the estimate; the gap is RFC
  packet-diagram and hex-format-spec false positives, plus one cross-repo
  issue citation that only coincidentally matched a PyPCAPKit PR number).
- 13 PR citations in .github/workflows/, matching the estimate exactly.
- Several citations named two or three numbers for one claim where a PR
  closed several issues, or several PRs closed the same issue;
  deduplicated rather than left reading "#425 and #425".

Four review rounds caught the same category error recurring: several sites
had relocated a verbatim quote or a specific finding into the issue number
rather than describing where the ruling was actually given, so the quote
no longer existed where the sentence pointed. Fixed each by naming the
issue while locating the ruling honestly -- "a ruling given in review of
the work for #N" -- the same shape already used on this repo's conventions
docs. Two sites needed the inverse correction instead: the #923 quote in
enum.py/exceptions.py genuinely is recorded on #923's own thread, just
attributed there to the pull request that implemented it, so those read
"a ruling recorded on GitHub issue #923" rather than pointing elsewhere.
Also fixed a lost conjunction and an ordinal/number mismatch in
corekit/enum.py, a self-contradicting below/above pointer repeated across
three internet/ files, and a number collision in http.py where one issue
ended up naming both a defect and the change that closed it.

Final sweep: grepped the whole tree for the word "verbatim" -- the marker
that makes a quote-attribution claim falsifiable -- across all 30 files
under pcapkit/ that carry it, and checked every quote this way names
against the actual issue thread. Caught two more of the same defect:
vendor/__main__.py's #872 citation (the quote is in the implementing pull
request's review, not #872 itself) and four sites across mh.py
attributing to #935 a ruling that only exists in the review of the pull
request that implemented it -- #935's own thread holds just the
superseded widen-not-delete proposal. Both fixed the same way. Every
other quote-bearing claim the sweep found -- #911, #937, three distinct
#877 quotes, both #842 quotes, and the #860/#808/#806/#886/#917 rewrites
from earlier in this pass -- resolves to the thread it names.

Verified: targeted pytest across every touched module passes, including
the test that pins the vendor/const apptype.py get() region as
byte-identical, reconfirmed after each amendment. Both edited workflow
YAML files parse before and after with unchanged key counts.

* docs(corekit): cite #719, not #937, for the AbsentType ruling

AbsentType's docstring attributed the owner's "document it as private
type/class... not for public use is enough" quote to #937. #937 itself
quotes that ruling verbatim under "The owner's ruling, verbatim (from
#719)" -- it re-attributes rather than originates it. Per the house
rule to cite the issue a ruling was settled on
(docs/source/contributing/conventions/documentation.rst:196-200), point
the attribution at #719 and re-wrap the paragraph to the file's
existing ~78-column width. The neighbouring, unrelated #937 citation
describing what #937 did to sentinel naming is untouched.

tests/corekit/ passes (400 passed, 16 skipped) against this worktree's
own pcapkit (confirmed via pcapkit.__file__); pylint on the file is
9.77/10, unchanged by this edit -- the one finding is a pre-existing,
unrelated too-few-public-methods warning on NoValueType.

* docs(tests): re-point six ruling citations at their actual threads, per #719

Swept tests/ for owner-ruling quotes attributed to the wrong GitHub
thread, the same defect class #719 fixed under pcapkit/. Confirmed each
by grepping the quote's distinctive text against the cited thread's
body/comments; a hit elsewhere is a re-quote or a different thread's
own words, not the source.

- test_sentinel_exports_unit.py: the already-reported #937->#719 fix
  for AbsentType's privacy ruling.
- test_enum_lookup_reparent_930_unit.py (4 sites) and test_mh_unit.py:
  "I prefer (2) directly" and the question that drew it are in pull
  request #940's thread, not issue #935 -- #935 only carries the first
  ruling ("I lean on 1").
- test_vendor_snapshot_restore_unit.py: the contextlib/atomic-write
  ruling is in pull request #873's thread; issue #872 has zero
  comments.
- test_vendor_reg_apptype_generator_unit.py (2 sites): the "undefined
  direct uses 0" ruling is in pull request #874's thread, not issue
  #860 or #770.
- test_const_enum_no_mint.py (2 sites): the mint/unmint criterion was
  settled on pull request #847 and confirmed on #775 -- the reverse of
  what the text said, per #861's own description of the same ruling;
  and "Q1 - bare it is." is pull request #838's thread, not #775's.

One occurrence left unresolved rather than guessed at: the "Preserve
each branch's existing name argument..." quote (4 sites in
test_const_enum_no_mint.py, attributed to "#775's final round") does
not appear verbatim in #775, #847, or #878 (the implementing PR) by
body, comments, review comments, or commit message -- only a
paraphrase in #878's own PR description/commit message, which is the
author's prose rather than a quoted ruling. Flagged for the owner
rather than fixed.

tests/corekit/, tests/vendor/, tests/const/ pass (400/16, 118, 299
respectively, pcapkit.__file__ confirmed inside this worktree);
tests/protocols/internet/test_mh_unit.py passes standalone (52/0) --
the full directory has 5 unrelated pre-existing failures from
ungenerated examples/captures/ fixtures, untouched by this change.

Refs #719

* docs(tests): paraphrase four fabricated or altered owner quotations (#719)

Per #719's citation ruling (de-quote, never reproduce a verbatim quote that
may have come from outside GitHub):

- test_const_enum_no_mint.py (4 sites): a quotation attributed to "the
  owner's ruling, verbatim" never appears in #775, #847, #861 or #878 (or
  anywhere in the repo's comment corpus). Replaced with a paraphrase
  attributed to PR #878's own body, which carries the real design note in
  different words.
- test_sentinel_exports_unit.py / test_const_registry_protocol.py: a quote
  attributed to #911 silently dropped half of what the owner wrote on #719
  and swapped `__all__` for "users". Replaced with a paraphrase naming #719
  as where it was settled and #911 as the issue that carried it out.
- test_const_enum_no_mint.py / test_const_enum_builtin_parity.py (4 sites):
  a "verbatim" quote of #860 silently corrected the owner's typo ("entires"
  -> "entries"). Paraphrased, which drops the question of reproducing or
  flagging the typo.
- test_enum_lookup_reparent_930_unit.py: "the owner's final ruling there"
  had #935 as its nearest antecedent instead of #940; named #940 explicitly
  and paraphrased the adjacent quote.

Verified: ast.parse and reST markup pairing clean on every touched file;
tests/const (299 tests) and the targeted pytest sweep of all touched files
(261 passed, 2013 subtests) are green. tests/corekit's full discover run
shows 5 pre-existing failures in test_sentinel_exports_unit.py, confirmed
identical on the unedited originals -- a cross-file test-order dependency
unrelated to this change.

* test(vendor,corekit): fix a surviving fabricated ruling and a wrong citation (#719)

- tests/vendor/test_ipx_socket_unit.py: the "owner's ruling" attribution for
  keeping the hex-suffixed Xerox name survived in this file after the prior
  commit removed the same false attribution from four sites in
  test_const_enum_no_mint.py. Reworded to credit PR #878's own design note,
  matching the wording already used at the repaired sites.
- tests/corekit/test_sentinel_exports_unit.py: the docstring cited the #719
  export ruling ("only export objects, not types") as grounds for keeping
  ABSENT out of __all__, but ABSENT is an object, so that ruling argues for
  including it, not excluding it. Re-grounded the sentence on the privacy
  ruling already quoted ~15 lines below instead, without re-quoting it.

Both changes are prose-only: tokenizing each file before and after with
comments and docstrings stripped produces identical token sequences.
tests/vendor passes 118/118 except one pre-existing, test-order-dependent
flake in test_vendor_snapshot_restore_unit.py (reproduces identically on the
pre-edit tree); tests/project/test_conventions_doc_claims.py passes 38/38.

* test(corekit,const): narrow the blanket paraphrase, restoring quotations that cite correctly (#719)

The last two commits paraphrased every disputed owner quotation away.
That was right for one case and wrong for two: a quotation that exists
nowhere has to be paraphrased, but a quotation that is real and was
only cited to the wrong thread lost its audit trail for nothing, since
the defect was the pointer, not the words. Per the owner's ruling,
narrow the fix to match.

Restored as quotations, correctly cited:

- tests/corekit/test_sentinel_exports_unit.py (~L4-7) and
  tests/const/test_const_registry_protocol.py (~L1363): the sentinel
  export rule, split back into its two real sources instead of one
  spliced sentence -- #719's "we should ONLY export the objects ...
  and leave the types ... out", and #911's own "we only expose the
  final objects to users", with #911 noted as both executor and
  source.

- tests/const/test_const_enum_no_mint.py (~L88, ~L1876, ~L2363) and
  tests/const/test_const_enum_builtin_parity.py (~L655): the #860
  minting ruling, including its load-bearing first sentence ("I think
  we should not mint on get still actually") and the owner's own
  "entires" typo, marked [sic] rather than silently corrected.

Left alone: the four #878 fabricated-quote sites in
test_const_enum_no_mint.py, which cite no real thread and stay
paraphrased, and the ABSENT privacy sentence, which is a correct
paraphrase of a different ruling.

Verified: ast.parse and reST markup clean on all four files; code
token sequences (docstrings/comments stripped) identical before and
after; each restored quotation substring-matches its source comment
after whitespace/markup normalisation. tests/const: 299 OK. tests/
project/test_conventions_doc_claims: 38 OK, 1 skipped.

* test(corekit,const): convert restored quotations to statements with context, per #719

The previous commit restored eight verbatim quotations to fix a narrowing
that had dropped their context. The owner has since ruled that neither
form is right: a narrowed paraphrase without context does not help a
reader who was not in the thread, but a verbatim quotation makes the
docstring read as a discussion rather than documentation.

- Sentinel export rule (corekit/test_sentinel_exports_unit.py,
  const/test_const_registry_protocol.py): state that a module's `__all__`
  lists a sentinel's object but deliberately leaves its type out, and why
  (the type is not part of the public surface), citing #719 as where it
  was settled and #911 as where the implementing work belongs.
- #860 minting rule, four sites (const/test_const_enum_no_mint.py x3,
  const/test_const_enum_builtin_parity.py): state that `get()` must not
  mint and only `register()` creates a new entry, and why (only
  IANA-registered values are legitimate and `get()` lacks the information
  to construct one), citing #860. Each site is fitted to its own
  surrounding prose rather than one paragraph pasted four times. Drops
  the `[sic]` each quotation carried, since there is nothing left to
  reproduce.
- Fixed two sentences left orphaned by the quotations' removal: an
  antecedent ("the three") that depended on the deleted quote's wording,
  and a sentence whose "get() as well as _missing_" had the emphasis
  backwards relative to the rule's own subject.

The four PR #878 paraphrase sites in test_const_enum_no_mint.py were
already in this third form and are unchanged.

Verified: ast.parse on all four files; tokenize with comments and
docstrings stripped shows an identical token sequence before/after
(prose-only); tests/const (299) and tests/project/test_conventions_doc_claims.py
(38, 1 skip) pass; tests/corekit (400, 5 failures, 16 skipped) matches the
documented pre-existing sentinel-identity failures.

* test(corekit,const): state the remaining owner rulings in our own words, per #719

The four files still carried owner-attributed quotations beside the eight
converted earlier, so each read half as documentation and half as a thread.

- Replace each quoted ruling with a statement of the rule, the reason a
  reader needs, and the issue where it was given (#842, #864, #775, #860,
  #911, #719, #647, #808, #759, #857).
- Rename the dangling "privacy ruling quoted below" reference to point at
  the statement that replaced the quotation.
- Leave RFC text, code literals and ordinary prose untouched.

Prose only: tokens with comments and docstrings stripped are identical
before and after; tests/const 299 OK, tests/corekit unchanged (5 known).

* test(const): restore ruling citations to the pull requests that carry them, per #719

tests/ is exempt from the issue-citation rule (documentation.rst, ruled on
#719): the fact cited lives in the pull request, not the issue.

- PR #836 restored for the TransportProtocol-extension refusal, the
  |-composite decoding retirement, and the stale-comment deletion; the
  rulings are not on #808 at all.
- PR #783 for the f-string convention; PR #847 for the mint criterion.
- The de-quotation stands: wording stays as statements, no quotation marks.
JarryShaw added a commit that referenced this pull request Oct 2, 2026
Part of #987, and a worse defect than the quotations that issue usually
removes: five sites presented an agent's own phrasing as the maintainer's
ruling.

Two phrases were attributed to him and appear in no comment anywhere. A fully
paginated search of all ~2117 issue and pull-request comments plus every inline
review comment finds "renaming anything" exactly once -- in the #982 review
that first reported this very invention -- and finds "who may claim this pool"
nowhere at all. "a real ownership fact" occurs only in an agent's own analysis
on #775 (5859210283, 3471 characters), and there it describes the Xerox row in
the IPX socket registry, not Xyplex.

- test_const_ethertype_862_unit.py no longer attributes the scoping to a
  ruling. PR #878's body is where it comes from, so the prose says so.
- test_const_enum_no_mint.py's Xyplex comment gave the wrong reason. The
  ruling's own reason, on #775 at 19:53:45Z, is that a proprietary protocol has
  no public name so the company name serves as one. Four sites carried the
  agent's gloss instead; all four now carry the real reason or the maintainer's
  mint-versus-notation criterion from #847.

#982 found this and named four lines; it was never fixed, and the sites had
since drifted. Where the phrase survives it is now unquoted and credited to PR
#878, which is what wrote it.

Prose only: with comments and NL dropped the token sequences are identical at
10751 each, the AST with docstrings blanked compares equal in both files,
test_const_ethertype_862_unit.py is identical once comments are masked, and no
assertion depends on any changed text. No file gains a line over 95 characters.
JarryShaw added a commit that referenced this pull request Oct 2, 2026
…ting them

The last tranche of #987, plus #995. These files are generated, so every change
is made twice: in the vendor template and identically in the const file it
renders. The template holds the prose verbatim with {NAME}/{DOCS} placeholders,
so the next crawler run reproduces it. No crawler was run.

Scope: 22 italic-quoted spans across 7 files, of which 16 are rulings and
converted. Six are not and stay -- all of them RFC 5797 and RFC 2389 text on
FEAT-code case sensitivity. The italic pattern also missed 14 straight-quoted
spans in the apptype pair, 7 per side, most wrapping a backticked vertical bar;
those are converted too.

- #877 was revised twice and the prose stated the middle revision. The final
  ruling is RFC-directed: an enum treats its values as case-insensitive where
  the RFC states they are, and as case-sensitive otherwise. The earlier form,
  which also allowed a fold where it logically made sense, is out.
- #860's ruling is narrowed to what it says. The prose called it the ruling for
  the whole family, but the comment reads "for all three" and names FEATCode,
  Command and Method. AppType is never named in it, and the AppType work is
  #874 under #860, so the prose now says the family follows a ruling given for
  those three rather than that it was given for the family.
- #860's FEAT-value question was answered conditionally, on whether it matched
  the approach already in use; that conditional is restored.
- The #921 exception ruling had lost its second clause -- that the exception
  comes from pcapkit.utilities.exceptions rather than being a builtin.
- #995: vendor/ipx/socket.py credited a ruling with "a real ownership fact",
  which is in no maintainer comment. The real reason, #847 at 13:15:36Z, is
  that a proprietary protocol may expose no name of its own. That comment is
  module documentation for UNASSIGNED_RANGE_NAMES and is not emitted into the
  const file, so only the template changed.
- Re-flowing wrapped one inline literal that the base had whole, and left five
  orphan tails. All six are closed.

Prose only, and proven against the one risk that matters in a generated file.
Importing both trees gives a byte-identical sha256 over every name and value for
the seven enums the three touched const files define -- 127 members, 126
iterable -- and the generated rST table rows are identical at 603 distinct of
707. Token sequences match per file with comments and NL dropped, masking
FSTRING_MIDDLE as well as STRING since the templates are f-strings and their
prose tokenises as the former. The over-95 line set is unchanged in every file.

Closes #995.
JarryShaw added a commit that referenced this pull request Oct 2, 2026
…ting them

The last tranche of #987, plus #995. These files are generated, so every change
is made twice: in the vendor template and identically in the const file it
renders. The template holds the prose verbatim with {NAME}/{DOCS} placeholders,
so the next crawler run reproduces it. No crawler was run.

Scope: 22 italic-quoted spans across 7 files, of which 16 are rulings and
converted. Six are not and stay -- all of them RFC 5797 and RFC 2389 text on
FEAT-code case sensitivity. The italic pattern also missed 14 straight-quoted
spans in the apptype pair, 7 per side, most wrapping a backticked vertical bar;
those are converted too.

- #877 was revised twice and the prose stated the middle revision. The final
  ruling is RFC-directed: an enum treats its values as case-insensitive where
  the RFC states they are, and as case-sensitive otherwise. The earlier form,
  which also allowed a fold where it logically made sense, is out.
- #860's ruling is narrowed to what it says. The prose called it the ruling for
  the whole family, but the comment reads "for all three" and names FEATCode,
  Command and Method. AppType is never named in it, and the AppType work is
  #874 under #860, so the prose now says the family follows a ruling given for
  those three rather than that it was given for the family.
- #860's FEAT-value question was answered conditionally, on whether it matched
  the approach already in use; that conditional is restored.
- The #921 exception ruling had lost its second clause -- that the exception
  comes from pcapkit.utilities.exceptions rather than being a builtin.
- #995: vendor/ipx/socket.py credited a ruling with "a real ownership fact",
  which is in no maintainer comment. The real reason, #847 at 13:15:36Z, is
  that a proprietary protocol may expose no name of its own. That comment is
  module documentation for UNASSIGNED_RANGE_NAMES and is not emitted into the
  const file, so only the template changed.
- The exception ruling was credited to issue #923, which carries no maintainer
  comment at all -- its own body attributes the ruling to the review of #877's
  implementation. So the prose now credits the ruling to that review and #923
  with the implementation, keeping the citation in issue form as
  docs/source/contributing/conventions/documentation.rst requires.
- Re-flowing wrapped one inline literal that the base had whole, and left five
  orphan tails. All six are closed.

Prose only, and proven against the one risk that matters in a generated file.
Importing both trees gives a byte-identical sha256 over every name and value for
the seven enums the three touched const files define -- 127 members, 126
iterable -- and the generated rST table rows are identical at 603 distinct of
707. Token sequences match per file with comments and NL dropped, masking
FSTRING_MIDDLE as well as STRING since the templates are f-strings and their
prose tokenises as the former. The over-95 line set is unchanged in every file.

Closes #995.
JarryShaw added a commit that referenced this pull request Oct 2, 2026
…ing pull requests issues

The last residual of #987 in tests/vendor/test_ipx_socket_unit.py.

- The retention of ``Registered by Xerox`` was credited to "a real ownership
  fact", which is in no maintainer comment -- it is the changelog's own phrase.
  The ruling is #775's: a proprietary protocol may expose no name of its own,
  so the company name serves as its name.
- Four lines called a pull request a "GitHub issue". Every number in the file
  was checked against the API: #492, #507, #775 and #841 are issues; #503,
  #847 and #878 are pull requests. The tests/ carve-out exempts this file from
  preferring the issue over the pull request, not from being accurate about
  which a number is.
- #847 is dropped rather than relabelled. The sentence claimed #775/#847
  converted three Socket ranges, and #847 converted none -- its own
  description puts the range branches out of scope, leaving them minting via
  extend_enum. Relabelling would have kept the false attribution. #841 stays
  where it belongs, as the temporal anchor for the branch-order work.

One ruling, one citation, in each of the three places that cite one.

tests/vendor/test_ipx_socket_unit.py passes: 10 passed, 19 subtests, exit code
0 read from the process rather than a summary line.
@JarryShaw JarryShaw added this to the 1.5 milestone Oct 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking Breaks public-facing behaviour or API (apply alongside the type label) const Regenerated IANA or vendor constant tables; members keep their numeric values fix Pull requests that fix a defect (fix: subject prefix)

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

reg: three Socket._missing_ range branches are unreachable, shadowed by a wider earlier branch

1 participant