Skip to content

fix(const,vendor): bring 8 bespoke registries onto EnumRegistry, stop them minting - #869

Merged
JarryShaw merged 1 commit into
mainfrom
fix/860-non-apptype-registries
Sep 28, 2026
Merged

JarryShaw merged 1 commit into
mainfrom
fix/860-non-apptype-registries

Conversation

@JarryShaw

@JarryShaw JarryShaw commented Sep 28, 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

Step 2 of #860 (PR 1 of 2; AppType is PR 2). Brings the 8 non-AppType bespoke registries onto EnumRegistry and applies the owner's #775 mint/unmint ruling, extended to these registries' get() as well as _missing_.

StatusCode, ReturnCode, ResponseKind, GroupingInformation, OptionType — 12 unambiguous placeholder branches (Unassigned, Unknown, opt_unknown) converted to _unregistered_member. Each of the three with a custom __new__ (StatusCode, ReturnCode, OptionType) gets its own override reconstructing the attributes the base's generic helper would otherwise leave unset. StatusCode/ReturnCode's hand-written get() (still on the retired default == -1 convention) is replaced by the base's — verified no caller in this tree relies on the old form. OptionType keeps its own get() (genuine multi-namespace dispatch), but round 2 review found get() itself still minted on both its int/namespace path and its str path — the live pcapng parse path (PCAPNG._make_pcapng_options) calls it with wire bytes, so parsing an undeclared option code was still registering a permanent member. Both paths now build an unregistered member too, and _unregistered_member still never touches __members_ns__ on any of the three paths.

FEATCode, Command, Method — these mint the literal, unmodified wire value as its own name rather than any manufactured placeholder. The owner ruled: "I think we should not mint on get still actually... get will not have sufficient information to create new ones." Command needs feat/desc/type/conf and Method needs safe/idempotent, neither of which a bare wire string carries. Both _missing_ and each class's own get() (a second, independent mint site bypassing _missing_) now build an unregistered member instead.

FEATCode's own fix: the crawler now declares all 15 real FEAT code values from the live IANA table (5 group markers + 10 per-command keywords) instead of minting the 10 as a side effect of evaluating Command's own rows at import time — the same import-time-mutation shape #861 removed from FilterType. Pinned count-agnostically (every name in __members__ must be a real declaration in the generated source), not with a hardcoded member count, since a future IANA table update would otherwise fail a correct regeneration.

Untouched, per explicit rulings: CommandType stays IntFlag (real A|P composites in the generated data); TransportProtocol's auto() change and AppType itself are PR 2's territory.

All 5 crawlers regenerated via python -m pcapkit.vendor <module>; git status --porcelain pcapkit/const is empty afterward, and a third regeneration produced byte-identical output. mypy/pylint findings the EnumRegistry mixin and the new overrides introduced are fixed or suppressed the way neighbouring code does; everything else remaining on the touched files is pre-existing and unrelated (verified against origin/main).

Tests: 239 methods across the seven touched test files, plus tests/protocols/misc/test_pcapng_unit.py (93 methods) — 332 total, all pass under coverage run. Touched const modules land at 92–100%: status_code.py's one miss is an unreachable exhaustive-guard fallback; option_type.py's remaining misses are pre-existing comparison dunders and an already-declared-member lookup branch, neither touched by this diff.

@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 28, 2026
@JarryShaw

Copy link
Copy Markdown
Owner Author

NEEDS CHANGES on bc19137eb — cross-review (opus; author sonnet). Three items. Everything else verified cleanly, including the parts I most expected to break.

1. OptionType.get still mints, on the live pcapng parse path, and the PR body says the opposite. I reproduced this myself, tree asserted:

_missing_ path: OptionType(9999)      -> <OptionType.opt_unknown: 9999> | members 40 -> 40
get() path:     OptionType.get(8888)  -> <OptionType.opt_unknown: 8888> | members 40 -> 41  MINTED

Two extend_enum calls survive, at pcapkit/const/pcapng/option_type.py:253 and :256 — the only ones left in all five const files. And pcapkit/protocols/misc/pcapng.py:4123 calls Enum_OptionType.get(int.from_bytes(schema[0:2], …), namespace=namespace) on wire bytes, so parsing a capture with an undeclared option code still registers a permanent member. The review also measured the namespace and str paths minting, and __members_ns__ growing with them.

The PR body's claim that an unregistered lookup "can't grow that side table" is false for the public get(). Worse, it is inconsistent with this PR's own rationale: Command.get/Method.get were converted precisely because leaving get() minting while _missing_ stopped would contradict a ruling that names get — same argument, same PR, opposite outcome on the third registry, with no distinction offered. By the standard already set for AppType.get's uncounted mint site, this PR's scope was 15 + 2, not 15.

Convert both sites. The reasoning is already in the PR. If you would rather defer, it needs to be stated in the PR body rather than discoverable only in a test docstring, plus a follow-up issue — but the coverage number tells against deferral: option_type.py measures 88%, and its missing lines include 254-256, exactly this branch.

2. Three new static-analysis findings, each against a c411d072a baseline. mypy went 11 → 10 overall (four genuine improvements) but gained three: Access to generic instance variables via class is ambiguous [misc] at http/method.py:219 and ftp/command.py:410 — both on lines the PR did not edit, caused by the EnumRegistry mixin, so they want # type: ignore[misc] — and an Unused "type: ignore" at vendor/ftp/command.py:284, which should simply be deleted. pylint gained W0201 Attribute '_name_' defined outside __init__ at option_type.py:229. isort clean on all ten.

3. Two numbers in the PR body do not reproduce. "452 tests" re-derives as 236 methods across the seven touched files, 0 failing (pytest separately reports 236 passed, 2276 subtests passed, so 452 matches neither). And "98–100%" holds for four of five files, not option_type.py at 88%.

Verified and sound, for the record: all eight _unregistered_member overrides exercise str(), repr() and every attribute __new__ sets with no AttributeError anywhere and no growth; ReturnCode's .kind/.group re-derivation is confirmed non-circular; the __members_ns__ pin was falsified by deliberately corrupting the table and the test caught it; keeping Command.get/Method.get as overrides is load-bearing — the base raises KeyError: 'retr' where the override resolves, which is verbatim #582/#583; the case canonicalisation problem is real and the fix risks nothing (zero non-upper values in either class); FEATCode is 15 members after import with zero rows referencing an undeclared code, and the count-agnostic guard would catch a re-introduced mint; regeneration is byte-identical with git status --porcelain empty; and all five pre-existing test changes are forced, with the assertIs relaxations net strengthenings — each replaced one assertion with three, adding assertNotIn(name, __members__), which states the property more strongly than assertIs ever did.

breaking confirmed and keeping it. CommandType and TransportProtocol byte-identical to main.

@JarryShaw JarryShaw added review: needs-changes Cross-review at the current head says changes are required; see the verdict comment and removed review: pending No verdict for the current head - never reviewed, or the head moved since the last one labels Sep 28, 2026
@JarryShaw
JarryShaw force-pushed the fix/860-non-apptype-registries branch from bc19137 to 3977c03 Compare September 28, 2026 04:07
@JarryShaw JarryShaw added review: pending No verdict for the current head - never reviewed, or the head moved since the last one and removed review: needs-changes Cross-review at the current head says changes are required; see the verdict comment labels Sep 28, 2026
@JarryShaw

Copy link
Copy Markdown
Owner Author

NEEDS CHANGES on 3977c0352 — cross-review (opus; author sonnet). Three items, each reproduced by me.

1. An undocumented casing change in Command._missing_. Measured on main (c411d072a) against the branch, same probe:

main    Command('xyzw')  str payload 'xyzw'  _value_ 'xyzw'  == 'xyzw': True
branch  Command('xyzw')  str payload 'XYZW'  _value_ 'XYZW'  == 'xyzw': False

Command is a StrEnum, so that is a public-contract flip for any caller comparing an unregistered command to the casing it arrived in. Method is different and the report's framing there is wrong: on main its unminted member carried an empty str payload (str(Method('frob')) == ''), so the branch's 'FROB' is an improvement rather than a regression. Either way it is silent, and FEATCode deliberately goes the other way — FEATCode('zork').value == 'zork' on both trees. Pick one convention, say so in the docstring, pin it with a test.

2. The AST checker's narrowing leaves the hole PR 2 walks into. tests/const/test_const_enum_no_mint.py:914-943 flags only %d/%i/%u in a literal format string, so 'x_%s' % value, 'x_%x' % value, 'x_' + str(value) and 'x_{}'.format(value) all pass. That is exactly the shape the next PR converts: 52 lines of '…_0x%s' % hex(value)[2:].upper().zfill(4) in pcapkit/const/reg/ethertype.py, plus ipx/socket.py:83 and mh/cga_type.py:54. Key on which operand is substituted rather than on the format spec — the only site that needed the exemption is '%s_unknown' % namespace, where the substituted operand is not the value.

3. The PR body's "401 total" is wrong — it is 331. 238 across the seven touched suites (33/8/50/74/9/59/5) plus 93 in tests/protocols/misc/test_pcapng_unit.py. My own run on this head: TOTAL run=331 fail=0 err=0.

Non-blocking: the new pcapkit/protocols/schema/misc/pcapng.py:576-588 docstring says deepcopy also fails on the plain-built member. Only pickle does — Enum.__copy__ short-circuits on 3.11+. Drop /deepcopy or scope it to 3.10.

Confirmed and not disputed: no minting on any path (get() int/namespace/str and _missing_ all leave __members__ at 40 and __members_ns__ identical), no extend_enum left in any of the 8 registries, Command.get('retr') and Method.get('get') keep their case-insensitive dispatch, and no declared member counts changed. CI on this head is 59 green / 0 failed.

@JarryShaw JarryShaw added review: needs-changes Cross-review at the current head says changes are required; see the verdict comment and removed review: pending No verdict for the current head - never reviewed, or the head moved since the last one labels Sep 28, 2026
@JarryShaw
JarryShaw force-pushed the fix/860-non-apptype-registries branch from 3977c03 to 517b177 Compare September 28, 2026 04:49
@JarryShaw JarryShaw added review: pending No verdict for the current head - never reviewed, or the head moved since the last one and removed review: needs-changes Cross-review at the current head says changes are required; see the verdict comment labels Sep 28, 2026
@JarryShaw

Copy link
Copy Markdown
Owner Author

NEEDS CHANGES on 517b1775e — cross-review (opus; author sonnet). The code is sound this round; all four items are committed prose or guard-rail reach. Each reproduced by me.

1. Two false statements in the new pcapkit/protocols/schema/misc/pcapng.py docstring. It names the wrong operation and the wrong mechanism:

pickle.dumps   OK len=85
pickle.loads   RAISED ValueError: 'opt_probe [8888]' is not a valid OptionType
deepcopy       -> <OptionType.opt_probe: 8888>
aenum.Enum has __copy__: False | __deepcopy__: False   (OptionType is an aenum subclass)

dumps succeeds — the failure is on loads. And the cited Enum.__copy__/__deepcopy__ short-circuit cannot be why deepcopy survives, because aenum's Enum defines neither; it survives because __reduce_ex__ rebuilds an equivalent member through _missing_. The round-trip conclusion stands; the two supporting facts do not.

2. pcapkit/const/http/method.py overclaims a fix and hides an asymmetry. Measured on this head:

Method.GET       value='GET'  str=''      len=0  == 'GET': False
Method('frob')   value='frob' str='frob'  len=4  == 'frob': True

__new__ is untouched, so all 40 registered members keep the empty str payload while unregistered ones now get a real one. On main both were empty — consistent. Drop "incidentally also fixes a pre-existing defect of this class's own __new__" and state the asymmetry, or fix __new__ too. I am filing the registered-member half separately; it predates this PR.

3. pcapkit/corekit/enum.py:292-294 is falsified by this PR and still committed. It cites FEATCode's _missing_ as minting "directly, via extend_enum"; here FEATCode('zork') leaves __members__ at 15 and the extend_enum call is gone. git diff --name-only origin/main...HEAD -- pcapkit/corekit/enum.py is empty, so fix it in this PR rather than leaving main briefly self-contradicting. AppType still mints, so the design decision itself stands — only its named witness is wrong.

4. The re-keyed checker is disarmed by any outer wrapper. _substituted_operands (tests/const/test_const_enum_no_mint.py:835-857) returns None for an ast.Call whose func.attr != 'format', which short-circuits is_manufactured to False — so ('x_%s' % value).upper(), str('x_%s' % value) and ''.join(['x_', str(value)]) all pass. .upper().zfill(4) is a real idiom inside the very %-expression the next PR converts, so hoisting it outward silently turns the guard off. Recurse through non-format Call/Attribute receivers.

Verified and not disputed: hex(value) is caught, so the guard is not inert for the 52 reg/ethertype.py sites; 244 call sites re-derived independently; the self-check fixtures fail under three separate mutations; all five crawlers regenerate byte-identically from a live IANA fetch; mypy pcapkit/vendor/ftp/command.py is clean, so the deleted [override] ignore was right; and 332 methods pass, 0 failures. Still UNVERIFIED: pylint on the two attribute-defined-outside-init sites.

@JarryShaw JarryShaw added review: needs-changes Cross-review at the current head says changes are required; see the verdict comment and removed review: pending No verdict for the current head - never reviewed, or the head moved since the last one labels Sep 28, 2026
@JarryShaw
JarryShaw force-pushed the fix/860-non-apptype-registries branch from 517b177 to e9c76d7 Compare September 28, 2026 05:26
@JarryShaw JarryShaw added review: pending No verdict for the current head - never reviewed, or the head moved since the last one and removed review: needs-changes Cross-review at the current head says changes are required; see the verdict comment labels Sep 28, 2026
@JarryShaw

Copy link
Copy Markdown
Owner Author

Correction to my round-3 verdict, item 1. I said deepcopy survives "because __reduce_ex__ rebuilds an equivalent member through _missing_". That is wrong, and the author caught it. Measured on e9c76d733:

issubclass(aenum.Enum, enum.Enum): True
'__deepcopy__' in vars(enum.Enum): True | '__copy__': True
copy.deepcopy(m) is m: True   copy.copy(m) is m: True
type(m).__deepcopy__ -> <function Enum.__deepcopy__ ...>
m.__reduce_ex__(4) -> (<aenum 'OptionType'>, ('opt_probe [8888]',))
pickle round trip RAISED ValueError: 'opt_probe [8888]' is not a valid OptionType

aenum.Enum subclasses the stdlib enum.Enum, which defines __copy__/__deepcopy__ as return self, so deepcopy short-circuits to the identical object and __reduce_ex__ is never reached — the same __reduce_ex__ that makes pickle.loads fail. My vars(aenum.Enum) check missed the inherited method, so I drew the right conclusion (deepcopy succeeds, pickle does not) from the wrong mechanism.

What stands from that item: pickle.dumps succeeds and loads is what raises, and the docstring's original "reachable in an already-loaded module" framing was wrong — enum.Enum.__deepcopy__ is an unconditional return self, with no reachability test. Round 4's docstring now states the inherited short-circuit, which is what the measurements support.

@JarryShaw

Copy link
Copy Markdown
Owner Author

NEEDS CHANGES on e9c76d733 — cross-review (opus; author sonnet). Two prose defects in the text round 4 added; the code is sound and CI is 59 green. Both reproduced by me.

1. The pickle clause in pcapkit/protocols/schema/misc/pcapng.py blames the wrong method, and its stated cause is false of the method it names. Measured:

BASE     EnumRegistry._unregistered_member(OptionType, 8888, 'opt_unknown')
         _value_=8888   reduce=(<aenum 'OptionType'>, (8888,))   roundtrip -> opt_unknown   members 40
OVERRIDE OptionType._unregistered_member(8888, 'opt_unknown')
         _value_='opt_unknown [8888]'   dumps OK   loads RAISED ValueError: 'opt_unknown [8888]' is not a valid OptionType

The base helper sets _value_ to the raw int, so it round-trips cleanly — the opposite of what the docstring asserts. What fails is OptionType's own override (pcapkit/const/pcapng/option_type.py:203-235), which is what get()'s miss path actually calls and which sets _value_ to the formatted display string. The paragraph is self-contradictory as written, because the reason it gives is a property of the override alone. Its conclusion is right and load-bearing — EnumField._unregistered_member does install a per-instance __reduce_ex__ and does round-trip, so post_process still cannot call get() unconditionally. Only the attribution needs moving.

2. The AppType witness at pcapkit/corekit/enum.py:292-294 is unreachable — the same failure as the FEATCode witness it replaced. Measured:

issubclass(AppType, EnumRegistry): False   (its own get() is AppType.get, so EnumRegistry.get never runs for it)
AppType.get('pypcapkit869probename') RAISED ValueError: ... is not a valid port number for AppType   members 0->0

AppType._missing_ rejects any non-int before reaching a mint, so a failed name lookup can never mint there. And there is no valid substitute: across 119 EnumRegistry subclasses under pcapkit.const, the str-valued ones are Command, FEATCode, Method, OptionType and the live minters are Socket, CGAType, EtherType — all int-valued. The intersection is empty once this PR lands, so say the restriction is defensive with no live witness in this tree, and that the remaining minters are int-valued so a str name could not reach their mint anyway.

Verified and not disputed: the deepcopy clause is now correct with no overreach; the Method asymmetry statement is accurate on both trees (all 40 registered members str() to '' on main and here alike) and pinned by a test citing #870; the enum.py hunk is docs-only (--numstat → 5 4, all inside get's docstring); the checker catches every live shape including % hex(value), the mapping form, nested join, walrus and f-string conversions; the fixtures fail under both mutations; 244 sites / 0 offenders re-derived; mypy pcapkit/vendor/ftp/command.py clean; 332 methods, 0 failures.

Latent, not live, and worth closing while we are here: is_manufactured returns False for a bare ast.Name, so on the call-recursion path a value passed as a plain argument is invisible — ''.join({...}), ''.join(str(v) for v in [value]), 'x_%s'.__mod__(value), operator.mod, format_map, and % self._value_ all slip through. No such shape exists under pcapkit/const/ today (census of the 244 name arguments: 233 Constant, 9 Name, 1 Call, 1 BinOp).

@JarryShaw JarryShaw added review: needs-changes Cross-review at the current head says changes are required; see the verdict comment and removed review: pending No verdict for the current head - never reviewed, or the head moved since the last one labels Sep 28, 2026
@JarryShaw
JarryShaw force-pushed the fix/860-non-apptype-registries branch from e9c76d7 to c8396d0 Compare September 28, 2026 06:04
@JarryShaw JarryShaw added review: pending No verdict for the current head - never reviewed, or the head moved since the last one and removed review: needs-changes Cross-review at the current head says changes are required; see the verdict comment labels Sep 28, 2026
… them minting (#860)

- StatusCode, ReturnCode, ResponseKind, GroupingInformation, OptionType,
  Command, Method and FEATCode now inherit EnumRegistry, gaining
  get_all/register/register_alias for the first time.
- Convert their 15 _missing_ branches -- plus Command's, Method's and
  OptionType's own get(), independent mint sites bypassing _missing_
  entirely -- to _unregistered_member, per the owner's #860 ruling:
  get/_missing_ cannot supply the attributes a real member needs, so only
  register() may mint. OptionType's get() has two such sites (an
  int/namespace path and a str path); both convert.
- Add per-class _unregistered_member overrides for StatusCode, ReturnCode,
  Command and Method, reconstructing the extra attributes a custom __new__
  sets that the base's generic helper would otherwise leave unset.
  OptionType's is fully bespoke, to avoid growing its own __members_ns__
  side table the way the base's helper is not entitled to -- verified on
  all three of its get()/_missing_ paths, including the live pcapng parse
  path that calls get() with wire bytes.
- Command, Method and FEATCode share one convention for an unregistered
  member's value: the caller's own casing, unchanged -- only the lookup
  name is canonicalised to upper case. This matches FEATCode's and
  Command's own pre-#860 behaviour exactly (so `Command('xyzw') ==
  'xyzw'` still holds, which an earlier revision of this change broke by
  canonicalising the value too). Method's own __new__ is untouched and
  left with its existing, separate defect (all 40 registered members'
  str payload is permanently empty, e.g. `Method.GET == 'GET'` is False)
  -- tracked as #870, not fixed here, so an unregistered Method member
  now carries real content while every registered one still does not.
- Declare FEATCode's 10 per-command keywords as real members instead of
  minting them as a side effect of evaluating Command's own rows at
  import time.
- Replace StatusCode's and ReturnCode's hand-written get() with the base's
  (no caller in this tree relies on the retired `default == -1` form);
  keep Command's, Method's and OptionType's own get(), each of which does
  real dispatch (case-insensitive matching; multi-namespace lookup) the
  base does not replicate.
- Regenerate all 5 crawlers via `python -m pcapkit.vendor`.
- Fix the mypy/pylint findings the EnumRegistry mixin and the new
  _unregistered_member overrides introduced (generic-instance-access
  ambiguity, a now-redundant type: ignore, an outside-__init__ attribute).
- The AST sweep guarding every _unregistered_member call's name argument
  keys on which operand is combined into the result -- via %, +, f-string,
  format, join, or any wrapping call around one, walking every call
  argument (not just its receiver) for a value/key reference regardless
  of nesting -- so a %s/.format()/f-string/concatenation/join/format_map
  that embeds the value is caught however it is spelled or wrapped. The
  argument walk is intentionally blunt (documented as such, with its
  known false-positive classes named): a false positive is loud and gets
  a fixture, a false negative ships quietly, and no real call site under
  pcapkit/const or pcapkit/vendor is affected either way. One heuristic
  gap is knowingly left latent and named in the docstring: an attribute
  alias like `self._value_` in place of the `value` parameter name
  itself.
- Correct pcapkit/corekit/enum.py's own docstring, which cited FEATCode
  and then AppType as registries whose _missing_ still mints directly --
  neither reachable as a witness for the sentence it sits in (FEATCode no
  longer mints after this change; AppType never goes through this base's
  get() at all) -- with an honest statement that the restriction is
  defensive with no live witness in this tree, and that the registries
  which do still mint (Socket, CGAType, EtherType) are int-valued and so
  unreachable by it regardless.

Build: coverage run -m unittest across the touched const/vendor/protocol
suites plus tests/protocols/misc/test_pcapng_unit.py, 332 methods, all
pass. Every changed const module lands at 92-100% (status_code.py's one
miss is an unreachable exhaustive-guard fallback; option_type.py's
remaining misses are pre-existing comparison dunders and an
already-declared-member lookup branch, neither touched by this diff).
@JarryShaw
JarryShaw force-pushed the fix/860-non-apptype-registries branch from c8396d0 to 4d9ccbd Compare September 28, 2026 06:26
@JarryShaw JarryShaw added review: pending No verdict for the current head - never reviewed, or the head moved since the last one and removed review: needs-changes Cross-review at the current head says changes are required; see the verdict comment labels Sep 28, 2026
@JarryShaw

Copy link
Copy Markdown
Owner Author

GOOD TO GO on 4d9ccbdf0 — cross-review (opus; author sonnet), sixth and final round. Round 5's single blocker is fixed and I re-derived every load-bearing claim myself.

Round 6 is provably prose-only. Tokenizing c8396d0f1 against 4d9ccbdf0 — comments and NL/NEWLINE/INDENT/DEDENT dropped, every string literal collapsed — is identical on all five files: corekit/enum.py 543, protocols/schema/misc/pcapng.py 8764, const/pcapng/option_type.py 865, corekit/fields/numbers.py 1408, tests/const/test_const_enum_no_mint.py 8452. So nothing executable moved.

The replaced rationale is accurate clause by clause. Measured:

False value.upper()          True  str(value.upper())      True  NAMES.get(value)
False NAMES[value]           True  NAMES.get(value, {}).get('x')   True getattr(obj, value)
False NAMES[value].upper()   True  str(NAMES[value])       True  map(lambda value: value, namespace)
False str(lambda value: 'x') False helper(value=namespace)

Its Call-vs-Subscript split, its "nothing tracks binding, only spelling", and the value= keyword-name negative all hold. The pickle clause reproduces exactly: the base path's pickle.loads succeeds but returns value='opt_unknown [8888]' rather than the original 8888 — proving the reconstruction went through _missing_ and so through OptionType's override — and comparing the two raises AttributeError: 'OptionType' object has no attribute 'opt_value', while the base path's immediate failure is still repr().

Two optional wording nits, not worth a seventh round. The sweep figure is const-only (244 call sites there, 0 under pcapkit/vendor/, where every _unregistered_member occurrence is inside a generator template string), so the parenthetical reads wider than the measurement. And a lambda parameter spelled value flags only when the body references it — str(lambda value: 'x') is False, because ast.arg is not an ast.Name.

Six rounds: two on code, four on the accuracy of docstrings the earlier rounds wrote. 332 test methods, 0 failures, on two independent runs at this head.

Not reporting it ready to merge yet — 4 of 58 CheckRuns are still in flight (54 green, 0 failed). I will confirm when they land; the verdict itself does not change.

@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 28, 2026
@JarryShaw
JarryShaw merged commit 60b85e3 into main Sep 28, 2026
63 checks passed
@JarryShaw
JarryShaw deleted the fix/860-non-apptype-registries branch September 28, 2026 12:22
@JarryShaw JarryShaw removed the review: good-to-go Cross-review at the current head says ready; CI state is separate label Sep 28, 2026
JarryShaw added a commit that referenced this pull request Sep 28, 2026
…t minting (#860)

Step 2 of #860 (PR 2 of 2, following AppType's 8 non-AppType siblings in #869).

- Mix pcapkit.const.reg.apptype.apptype.AppType into EnumRegistry, alongside
  its four transport subclasses (TCP/UDP/SCTP/DCCP). AppType keeps its own
  get/get_all/register_alias, which already dispatch by transport protocol,
  and gains a working register (previously absent -- the base's generic one
  would have built a member with svc='<null>') and an _unregistered_member
  override reconstructing svc/port/proto.
- Convert AppType._missing_'s 766 range-bounded extend_enum calls, plus the
  one more inside get()'s own second mint site, to _unregistered_member --
  owner ruling: "only IANA registered ones are legit values ... get will not
  have sufficient information to create new ones." All 766+1 branches convert
  uniformly, including the 8 that named a real (if span-assigned rather than
  individually declared) service, since none of them mints at import time --
  unlike FEATCode's earlier fix, there is no self-mutation defect here to
  address by declaring members statically.
- Move TransportProtocol from power-of-two values to sequential auto(), per
  the owner's follow-up ruling once composite `|` values stopped being
  parsed at all; delete the stale comment claiming the values must stay
  power-of-two. No test pins the one accepted consequence (a composed proto
  can now silently resolve to another transport's real declared member --
  e.g. AppType.get(80, proto=tcp|udp) returns SCTP.http, where main raised),
  per the owner's explicit instruction.
- Update corekit/enum.py's own docstring, which described AppType's
  EnumRegistry mixin as future work ("stays as it is until tier two lands"),
  and its get() docstring's str-valued-registry census (119 -> 124).
- Update tests/vendor/test_vendor_reg_apptype_generator_unit.py's #770 pin,
  which asserted the old bare-literal-vs-auto() distinction that no longer
  exists now that every TransportProtocol member (undefined included) is
  auto()-valued and cast; the mypy-backed sibling test already tolerated the
  new shape unchanged.
- Fix four tests in the existing suite that pinned the old minting/power-of-
  two behaviour directly (test_const_apptype_split_unit.py,
  test_const_enum_builtin_parity.py), and add 17 new tests plus prose/count
  updates in test_const_enum_no_mint.py and test_const_registry_protocol.py.

All 5 crawlers regenerate byte-identically on a second run; git status is
clean relative to this commit. mypy/pylint deltas are the same classes of
finding this codebase already tolerates elsewhere (aenum stub gaps,
import-outside-toplevel/protected-access/no-member in test internals),
suppressed with # type: ignore[override]/pylint: disable=arguments-differ,
arguments-renamed where the codebase's own convention already does so.
403 test methods pass across the complete tests/const/ and
tests/protocols/transport/ directories, plus 87 across tests/vendor/
(excluding the live-network crawler-reachability test) and 55 across the
TransportProtocol-consuming suites outside those directories.
JarryShaw added a commit that referenced this pull request Sep 28, 2026
…t minting (#860)

Step 2 of #860 (PR 2 of 2, following AppType's 8 non-AppType siblings in #869).

- Mix pcapkit.const.reg.apptype.apptype.AppType into EnumRegistry, alongside
  its four transport subclasses (TCP/UDP/SCTP/DCCP). AppType keeps its own
  get/get_all/register_alias, which already dispatch by transport protocol,
  and gains a working register (previously absent -- the base's generic one
  would have built a member with svc='<null>') and an _unregistered_member
  override reconstructing svc/port/proto.
- Convert AppType._missing_'s 766 range-bounded extend_enum calls, plus the
  one more inside get()'s own second mint site, to _unregistered_member --
  owner ruling: "only IANA registered ones are legit values ... get will not
  have sufficient information to create new ones." All 766+1 branches convert
  uniformly, including the 8 that named a real (if span-assigned rather than
  individually declared) service, since none of them mints at import time --
  unlike FEATCode's earlier fix, there is no self-mutation defect here to
  address by declaring members statically.
- Move TransportProtocol from power-of-two values to sequential auto(), per
  the owner's follow-up ruling once composite `|` values stopped being
  parsed at all; delete the stale comment claiming the values must stay
  power-of-two. AppType._dispatch treats a composed or bare int identically
  as a whole either way, so the renumbering changes what specific integers
  mean, not only what hand-composed ones do -- e.g. a bare, uncomposed 4
  (previously sctp's value) now silently resolves as dccp's, with no
  exception, since a real member sits at 4 under either numbering. No test
  pins any of this, per the owner's explicit instruction; the class comment
  states it instead.
- Update corekit/enum.py's own docstring, which described AppType's
  EnumRegistry mixin as future work ("stays as it is until tier two lands"),
  and its get() docstring's str-valued-registry census (119 -> 124).
- Update tests/vendor/test_vendor_reg_apptype_generator_unit.py's #770 pin,
  which asserted the old bare-literal-vs-auto() distinction that no longer
  exists now that every TransportProtocol member (undefined included) is
  auto()-valued and cast; the mypy-backed sibling test already tolerated the
  new shape unchanged. Narrowed the docstring's claim to what the mypy run
  actually depends on (undefined alone -- measured: unwrapping tcp leaves
  the same mypy invocation clean), and corrected the second guard's own
  justification (it does not catch a single-edit "wrapper dropped"
  regression, the primary containment check already does; it catches a
  two-edit one, the correct line left in place alongside a stray unwrapped
  duplicate).
- Fix four tests in the existing suite that pinned the old minting/power-of-
  two behaviour directly (test_const_apptype_split_unit.py,
  test_const_enum_builtin_parity.py), and add 17 new tests plus prose/count
  updates in test_const_enum_no_mint.py and test_const_registry_protocol.py.

All 5 crawlers regenerate byte-identically on a second run; git status is
clean relative to this commit. mypy/pylint deltas are the same classes of
finding this codebase already tolerates elsewhere (aenum stub gaps,
import-outside-toplevel/protected-access/no-member in test internals),
suppressed with # type: ignore[override]/pylint: disable=arguments-differ,
arguments-renamed where the codebase's own convention already does so.
403 test methods pass across the complete tests/const/ and
tests/protocols/transport/ directories, plus 87 across tests/vendor/
(excluding the live-network crawler-reachability test) and 55 across the
TransportProtocol-consuming suites outside those directories.
JarryShaw added a commit that referenced this pull request Sep 28, 2026
…t minting (#860)

Step 2 of #860 (PR 2 of 2, following AppType's 8 non-AppType siblings in #869).

- Mix pcapkit.const.reg.apptype.apptype.AppType into EnumRegistry, alongside
  its four transport subclasses (TCP/UDP/SCTP/DCCP). AppType keeps its own
  get/get_all/register_alias, which already dispatch by transport protocol,
  and gains a working register (previously absent -- the base's generic one
  would have built a member with svc='<null>') and an _unregistered_member
  override reconstructing svc/port/proto.
- Convert AppType._missing_'s 766 range-bounded extend_enum calls, plus the
  one more inside get()'s own second mint site, to _unregistered_member --
  owner ruling: "only IANA registered ones are legit values ... get will not
  have sufficient information to create new ones." All 766+1 branches convert
  uniformly, including the 8 that named a real (if span-assigned rather than
  individually declared) service, since none of them mints at import time --
  unlike FEATCode's earlier fix, there is no self-mutation defect here to
  address by declaring members statically.
- Move TransportProtocol from power-of-two values to sequential auto(), per
  GitHub issue #836's ruling retiring `|`-composite decoding and the owner's
  further #860 ruling that the spacing itself then had nothing left to
  protect; delete the stale comment claiming the values must stay
  power-of-two. AppType._dispatch treats a composed or bare int identically
  as a whole either way, so the renumbering changes what specific integers
  mean, not only what hand-composed ones do -- e.g. a bare, uncomposed 4
  (previously sctp's value) now silently resolves as dccp's, with no
  exception, since a real member sits at 4 under either numbering. No test
  pins any of this, per the owner's explicit instruction; the class comment
  states it instead.
- Update corekit/enum.py's own docstring, which described AppType's
  EnumRegistry mixin as future work ("stays as it is until tier two lands"),
  and its get() docstring's str-valued-registry census (119 -> 124).
- Update tests/vendor/test_vendor_reg_apptype_generator_unit.py's #770 pin,
  which asserted the old bare-literal-vs-auto() distinction that no longer
  exists now that every TransportProtocol member (undefined included) is
  auto()-valued: under auto(), a member's own value infers as Any, which is
  assignable to TransportProtocol with no cast at all, so no single member's
  wrapper is load-bearing against a mypy error any more -- measured directly
  against all three shapes (baseline, undefined unwrapped, undefined
  reverted to the bare literal 0). What the mypy test still depends on is
  staying on auto() at all, not on which member is wrapped; its own "4
  errors" claim is corrected to the 3 [assignment] + 762 [arg-type] this
  tree's own get()/get_all() Union-typed proto (tolerates a bare int
  default) and the new _unregistered_member site (still plainly typed)
  actually produce once reverted that far.
- Fix four tests in the existing suite that pinned the old minting/power-of-
  two behaviour directly (test_const_apptype_split_unit.py,
  test_const_enum_builtin_parity.py), and add 17 new tests plus prose/count
  updates in test_const_enum_no_mint.py and test_const_registry_protocol.py.

All 5 crawlers regenerate byte-identically on a second run; git status is
clean relative to this commit. mypy/pylint deltas are the same classes of
finding this codebase already tolerates elsewhere (aenum stub gaps,
import-outside-toplevel/protected-access/no-member in test internals),
suppressed with # type: ignore[override]/pylint: disable=arguments-differ,
arguments-renamed where the codebase's own convention already does so.
403 test methods pass across the complete tests/const/ and
tests/protocols/transport/ directories, plus 87 across tests/vendor/
(excluding the live-network crawler-reachability test) and 55 across the
TransportProtocol-consuming suites outside those directories.
JarryShaw added a commit that referenced this pull request Sep 28, 2026
…t minting (#860)

Step 2 of #860 (PR 2 of 2, following AppType's 8 non-AppType siblings in #869).

- Mix pcapkit.const.reg.apptype.apptype.AppType into EnumRegistry, alongside
  its four transport subclasses (TCP/UDP/SCTP/DCCP). AppType keeps its own
  get/get_all/register_alias, which already dispatch by transport protocol,
  and gains a working register (previously absent -- the base's generic one
  would have built a member with svc='<null>') and an _unregistered_member
  override reconstructing svc/port/proto.
- Convert AppType._missing_'s 766 range-bounded extend_enum calls, plus the
  one more inside get()'s own second mint site, to _unregistered_member --
  owner ruling: "only IANA registered ones are legit values ... get will not
  have sufficient information to create new ones." All 766+1 branches convert
  uniformly, including the 8 that named a real (if span-assigned rather than
  individually declared) service, since none of them mints at import time --
  unlike FEATCode's earlier fix, there is no self-mutation defect here to
  address by declaring members statically.
- Move TransportProtocol from power-of-two values to sequential auto(), per
  PR #836's ruling retiring `|`-composite decoding and the owner's further
  #860 ruling that the spacing itself then had nothing left to protect;
  delete the stale comment claiming the values must stay power-of-two.
  AppType._dispatch treats a composed or bare int identically as a whole
  either way, so the renumbering changes what specific integers mean, not
  only what hand-composed ones do -- e.g. a bare, uncomposed 4 (previously
  sctp's value) now silently resolves as dccp's, with no exception, since a
  real member sits at 4 under either numbering. No test pins any of this,
  per the owner's explicit instruction; the class comment states it
  instead, and every docstring that used to claim a hand-built composite is
  refused unconditionally (_dispatch's and get's own) is corrected to say
  it is looked up as a whole and resolves or is refused depending on
  whether some real member happens to equal it.
- Update corekit/enum.py's own docstring, which described AppType's
  EnumRegistry mixin as future work ("stays as it is until tier two lands"),
  and its get() docstring's str-valued-registry census (119 -> 124).
- Update tests/vendor/test_vendor_reg_apptype_generator_unit.py's #770 pin,
  which asserted the old bare-literal-vs-auto() distinction that no longer
  exists now that every TransportProtocol member (undefined included) is
  auto()-valued: under auto(), a member's own value infers as Any, which is
  assignable to TransportProtocol with no cast at all, so no single member's
  wrapper is load-bearing against a mypy error any more -- measured directly
  against all three shapes (baseline, undefined unwrapped, undefined
  reverted to the bare literal 0). What the mypy test still depends on is
  staying on auto() at all, not on which member is wrapped; its "4 errors"
  claim is corrected to the 3 [assignment] + 762 [arg-type] this tree
  produces once reverted that far, and to the two separate changes that
  moved the count there: PR #836 widened get()/get_all()'s own proto
  annotations to tolerate a bare int default before this issue touched
  anything, and this issue's own new _unregistered_member site is what
  brought the count back up from 2 to 3.
- Fix four tests in the existing suite that pinned the old minting/power-of-
  two behaviour directly (test_const_apptype_split_unit.py,
  test_const_enum_builtin_parity.py), and add 17 new tests plus prose/count
  updates in test_const_enum_no_mint.py and test_const_registry_protocol.py.

All 5 crawlers regenerate byte-identically on a second run; git status is
clean relative to this commit. mypy/pylint deltas are the same classes of
finding this codebase already tolerates elsewhere (aenum stub gaps,
import-outside-toplevel/protected-access/no-member in test internals),
suppressed with # type: ignore[override]/pylint: disable=arguments-differ,
arguments-renamed where the codebase's own convention already does so.
403 test methods pass across the complete tests/const/ and
tests/protocols/transport/ directories, plus 87 across tests/vendor/
(excluding the live-network crawler-reachability test) and 55 across the
TransportProtocol-consuming suites outside those directories.
JarryShaw added a commit that referenced this pull request Sep 28, 2026
…t minting (#860)

Step 2 of #860 (PR 2 of 2, following AppType's 8 non-AppType siblings in #869).

- Mix pcapkit.const.reg.apptype.apptype.AppType into EnumRegistry, alongside
  its four transport subclasses (TCP/UDP/SCTP/DCCP). AppType keeps its own
  get/get_all/register_alias, which already dispatch by transport protocol,
  and gains a working register (previously absent -- the base's generic one
  would have built a member with svc='<null>') and an _unregistered_member
  override reconstructing svc/port/proto.
- Convert AppType._missing_'s 766 range-bounded extend_enum calls, plus the
  one more inside get()'s own second mint site, to _unregistered_member --
  owner ruling: "only IANA registered ones are legit values ... get will not
  have sufficient information to create new ones." All 766+1 branches convert
  uniformly, including the 8 that named a real (if span-assigned rather than
  individually declared) service, since none of them mints at import time --
  unlike FEATCode's earlier fix, there is no self-mutation defect here to
  address by declaring members statically.
- Move TransportProtocol from power-of-two values to sequential auto(), per
  PR #836's ruling retiring `|`-composite decoding and the owner's further
  #860 ruling that the spacing itself then had nothing left to protect;
  delete the stale comment claiming the values must stay power-of-two.
  AppType._dispatch treats a composed or bare int identically as a whole
  either way, so the renumbering changes what specific integers mean, not
  only what hand-composed ones do -- e.g. a bare, uncomposed 4 (previously
  sctp's value) now silently resolves as dccp's, with no exception, since a
  real member sits at 4 under either numbering. No test pins any of this,
  per the owner's explicit instruction; the class comment states it
  instead, and every docstring that used to claim a hand-built composite is
  refused unconditionally (_dispatch's and get's own) is corrected to say
  it is looked up as a whole and resolves or is refused depending on
  whether some real member happens to equal it. Also fixed a generator-only
  comment (process()'s own, no const twin) still claiming a member's proto
  "is a single bit" -- true under the old power-of-two spacing, not under
  auto().
- Update corekit/enum.py's own docstring, which described AppType's
  EnumRegistry mixin as future work ("stays as it is until tier two lands"),
  and its get() docstring's str-valued-registry census (119 -> 124).
- Update tests/vendor/test_vendor_reg_apptype_generator_unit.py's #770 pin,
  which asserted the old bare-literal-vs-auto() distinction that no longer
  exists now that every TransportProtocol member (undefined included) is
  auto()-valued: under auto(), a member's own value infers as Any, which is
  assignable to TransportProtocol with no cast at all, so no single member's
  wrapper is load-bearing against a mypy error any more -- measured directly
  against all three shapes (baseline, undefined unwrapped, undefined
  reverted to the bare literal 0). What the mypy test still depends on is
  staying on auto() at all, not on which member is wrapped; its "4 errors"
  claim is corrected to the 3 [assignment] + 762 [arg-type] this tree
  produces once reverted that far, and to the two separate changes that
  moved the count there: PR #836 widened get()/get_all()'s own proto
  annotations to tolerate a bare int default before this issue touched
  anything, and this issue's own new _unregistered_member site is what
  brought the count back up from 2 to 3.
- Fix four tests in the existing suite that pinned the old minting/power-of-
  two behaviour directly (test_const_apptype_split_unit.py,
  test_const_enum_builtin_parity.py), and add 17 new tests plus prose/count
  updates in test_const_enum_no_mint.py and test_const_registry_protocol.py.

All 5 crawlers regenerate byte-identically on a second run; git status is
clean relative to this commit. mypy/pylint deltas are the same classes of
finding this codebase already tolerates elsewhere (aenum stub gaps,
import-outside-toplevel/protected-access/no-member in test internals),
suppressed with # type: ignore[override]/pylint: disable=arguments-differ,
arguments-renamed where the codebase's own convention already does so.
403 test methods pass across the complete tests/const/ and
tests/protocols/transport/ directories, plus 87 across tests/vendor/
(excluding the live-network crawler-reachability test) and 55 across the
TransportProtocol-consuming suites outside those directories.
JarryShaw added a commit that referenced this pull request Sep 28, 2026
…t minting (#860)

Step 2 of #860 (PR 2 of 2, following AppType's 8 non-AppType siblings in #869).

- Mix pcapkit.const.reg.apptype.apptype.AppType into EnumRegistry, alongside
  its four transport subclasses (TCP/UDP/SCTP/DCCP). AppType keeps its own
  get/get_all/register_alias, which already dispatch by transport protocol,
  and gains a working register (previously absent -- the base's generic one
  would have built a member with svc='<null>') and an _unregistered_member
  override reconstructing svc/port/proto.
- Convert AppType._missing_'s 766 range-bounded extend_enum calls, plus the
  one more inside get()'s own second mint site, to _unregistered_member --
  owner ruling: "only IANA registered ones are legit values ... get will not
  have sufficient information to create new ones." All 766+1 branches convert
  uniformly, including the 8 that named a real (if span-assigned rather than
  individually declared) service, since none of them mints at import time --
  unlike FEATCode's earlier fix, there is no self-mutation defect here to
  address by declaring members statically.
- Move TransportProtocol from power-of-two values to sequential ones, per
  PR #836's ruling retiring `|`-composite decoding and the owner's further
  #860 ruling that the spacing itself then had nothing left to protect;
  delete the stale comment claiming the values must stay power-of-two.
  undefined is declared as an explicit cast('TransportProtocol', 0) and
  tcp/udp/sctp/dccp continue from it via plain auto(), per the owner's own
  final ruling on the declaration shape ("undefined direct uses 0. then
  other real transport use auto. so we don't have to define a _start_ and
  the undefined declaration is explicit") -- an earlier revision of this
  same change used an explicit _start_ = 0 with every member on auto(),
  which the owner's ruling superseded. AppType._dispatch treats a composed
  or bare int identically as a whole either way, so the renumbering changes
  what specific integers mean, not only what hand-composed ones do -- e.g.
  a bare, uncomposed 4 (previously sctp's value) now silently resolves as
  dccp's, with no exception, since a real member sits at 4 under either
  numbering. No test pins any of this, per the owner's explicit
  instruction; the class comment states it instead, and every docstring
  that used to claim a hand-built composite is refused unconditionally
  (_dispatch's and get's own) is corrected to say it is looked up as a
  whole and resolves or is refused depending on whether some real member
  happens to equal it.
- Update corekit/enum.py's own docstring, which described AppType's
  EnumRegistry mixin as future work ("stays as it is until tier two lands"),
  and its get() docstring's str-valued-registry census (119 -> 124).
- Update tests/vendor/test_vendor_reg_apptype_generator_unit.py's #770 pin:
  undefined is once again the one bare-literal-under-cast member among four
  auto()-valued siblings, exactly as #770 first shaped it, so its wrapper is
  load-bearing against a mypy error again -- measured directly, stripping
  it alone (leaving auto() elsewhere) now reproduces 3 [assignment] + 762
  [arg-type] errors (765 total), while stripping tcp's wrapper instead
  stays clean. The two separate changes behind the 3-not-4 count: PR #836
  widened get()/get_all()'s own proto annotations to tolerate a bare int
  default before this issue touched anything, and this issue's own new
  _unregistered_member site is what brought the count back up from 2 to 3.
- Fix four tests in the existing suite that pinned the old minting/power-of-
  two behaviour directly (test_const_apptype_split_unit.py,
  test_const_enum_builtin_parity.py), and add 17 new tests plus prose/count
  updates in test_const_enum_no_mint.py and test_const_registry_protocol.py.

All 5 crawlers regenerate byte-identically on a second run; git status is
clean relative to this commit. mypy/pylint deltas are the same classes of
finding this codebase already tolerates elsewhere (aenum stub gaps,
import-outside-toplevel/protected-access/no-member in test internals),
suppressed with # type: ignore[override]/pylint: disable=arguments-differ,
arguments-renamed where the codebase's own convention already does so.
216 test methods pass across test_const_apptype_split_unit.py,
test_const_enum_no_mint.py, test_const_enum_builtin_parity.py,
test_const_registry_protocol.py and test_vendor_reg_apptype_generator_unit.py,
plus 87 across tests/vendor/ (excluding the live-network crawler-
reachability test) and 55 across the TransportProtocol-consuming suites
outside those directories.
JarryShaw added a commit that referenced this pull request Sep 28, 2026
…t minting (#860)

Step 2 of #860 (PR 2 of 2, following AppType's 8 non-AppType siblings in #869).

- Mix pcapkit.const.reg.apptype.apptype.AppType into EnumRegistry, alongside
  its four transport subclasses (TCP/UDP/SCTP/DCCP). AppType keeps its own
  get/get_all/register_alias, which already dispatch by transport protocol,
  and gains a working register (previously absent -- the base's generic one
  would have built a member with svc='<null>') and an _unregistered_member
  override reconstructing svc/port/proto.
- Convert AppType._missing_'s 766 range-bounded extend_enum calls, plus the
  one more inside get()'s own second mint site, to _unregistered_member --
  owner ruling: "only IANA registered ones are legit values ... get will not
  have sufficient information to create new ones." All 766+1 branches convert
  uniformly, including the 8 that named a real (if span-assigned rather than
  individually declared) service, since none of them mints at import time --
  unlike FEATCode's earlier fix, there is no self-mutation defect here to
  address by declaring members statically.
- Move TransportProtocol from power-of-two values to sequential ones, per
  PR #836's ruling retiring `|`-composite decoding and the owner's further
  #860 ruling that the spacing itself then had nothing left to protect;
  delete the stale comment claiming the values must stay power-of-two.
  undefined is declared as an explicit cast('TransportProtocol', 0) and
  tcp/udp/sctp/dccp continue from it via plain auto(), per the owner's own
  final ruling on the declaration shape ("undefined direct uses 0. then
  other real transport use auto. so we don't have to define a _start_ and
  the undefined declaration is explicit") -- an earlier revision of this
  same change used an explicit _start_ = 0 with every member on auto(),
  which the owner's ruling superseded. AppType._dispatch treats a composed
  or bare int identically as a whole either way, so the renumbering changes
  what specific integers mean, not only what hand-composed ones do -- e.g.
  a bare, uncomposed 4 (previously sctp's value) now silently resolves as
  dccp's, with no exception, since a real member sits at 4 under either
  numbering. No test pins any of this, per the owner's explicit
  instruction; the class comment states it instead, and every docstring
  that used to claim a hand-built composite is refused unconditionally
  (_dispatch's and get's own) is corrected to say it is looked up as a
  whole and resolves or is refused depending on whether some real member
  happens to equal it.
- Update corekit/enum.py's own docstring, which described AppType's
  EnumRegistry mixin as future work ("stays as it is until tier two lands"),
  and its get() docstring's str-valued-registry census (119 -> 124).
- Update tests/vendor/test_vendor_reg_apptype_generator_unit.py's #770 pin:
  undefined is once again the one bare-literal-under-cast member among four
  auto()-valued siblings, exactly as #770 first shaped it, so its wrapper is
  load-bearing against a mypy error again -- measured directly, stripping
  it alone (leaving auto() elsewhere) now reproduces 3 [assignment] + 762
  [arg-type] errors (765 total), while stripping tcp's wrapper instead
  stays clean. The two separate changes behind the 3-not-4 count: PR #836
  widened get()/get_all()'s own proto annotations to tolerate a bare int
  default before this issue touched anything, and this issue's own new
  _unregistered_member site is what brought the count back up from 2 to 3.
- Fix four tests in the existing suite that pinned the old minting/power-of-
  two behaviour directly (test_const_apptype_split_unit.py,
  test_const_enum_builtin_parity.py), and add 17 new tests plus prose/count
  updates in test_const_enum_no_mint.py and test_const_registry_protocol.py.

All 5 crawlers regenerate byte-identically on a second run; git status is
clean relative to this commit. mypy/pylint deltas are the same classes of
finding this codebase already tolerates elsewhere (aenum stub gaps,
import-outside-toplevel/protected-access/no-member in test internals),
suppressed with # type: ignore[override]/pylint: disable=arguments-differ,
arguments-renamed where the codebase's own convention already does so.
216 test methods pass across test_const_apptype_split_unit.py,
test_const_enum_no_mint.py, test_const_enum_builtin_parity.py,
test_const_registry_protocol.py and test_vendor_reg_apptype_generator_unit.py,
plus 87 across tests/vendor/ (excluding the live-network crawler-
reachability test) and 55 across the TransportProtocol-consuming suites
outside those directories (tests/corekit/test_fields_numbers_port_option_
no_mint_unit.py, tests/dumpkit/test_nameless_enum_rendering_unit.py,
tests/dumpkit/test_common_unit.py, tests/foundation/registry/
test_protocols.py, tests/utilities/test_compat.py).
JarryShaw added a commit that referenced this pull request Sep 28, 2026
JarryShaw added a commit that referenced this pull request Sep 28, 2026
JarryShaw added a commit that referenced this pull request Sep 28, 2026
JarryShaw added a commit that referenced this pull request Oct 1, 2026
Three factual errors in test prose, found while surveying #NNN
citations under tests/ for #719:

- test_http_unit.py:2356-2365 claimed PR #457 was "still-open" and
  that the SETTINGS round trip "remains unreachable until that
  lands". Both were stale: #457 merged 2026-09-18, the
  `httpv2-frame/SETTINGS` key no longer exists in
  `EXPECTED_FAILURES` (verified by importing it: 43 keys, only
  httpv2 key is PRIORITY), and the round trip itself passes
  (reproduced: `httpv2.roundtrip()` reports 'OK' for that case).
  Rewrote the paragraph: the round trip works; what still raises
  `KeyError: 'flags'` is a bare `SettingsFrame(...).pack()` with no
  enclosing packet (reproduced directly), which is an unsupported
  invocation, not a round-trip defect. Cited `FrameType.post_process`
  by name rather than the stale `httpv2.py:144` line number (the
  real raise is at `packet['flags'][name]`, confirmed by traceback).
  `GH-445` is left alone -- it is this repo's own issue shorthand,
  used throughout pcapkit/ and tests/, and #445 is in fact an issue.
- test_base_class_contract.py:45 called #547 and #570 "issues";
  both are pull requests.
- test_const_str_payload_870_unit.py:12 called #869 a "GitHub
  issue"; it is a pull request.

No behaviour or citation-style changes -- tests/** is exempt from
the #719 PR-citation rule. Ran each file individually under pytest
and plain unittest (all three use subTest): 6/6, 7/7, 60/60 passed
both ways.
JarryShaw added a commit that referenced this pull request Oct 1, 2026
Three factual errors in test prose, found while surveying #NNN
citations under tests/ for #719:

- test_http_unit.py:2356-2365 claimed PR #457 was "still-open" and
  that the SETTINGS round trip "remains unreachable until that
  lands". Both were stale: #457 merged 2026-09-18, the
  `httpv2-frame/SETTINGS` key no longer exists in
  `EXPECTED_FAILURES` (verified by importing it: 43 keys, only
  httpv2 key is PRIORITY), and the round trip itself passes
  (reproduced: `httpv2.roundtrip()` reports 'OK' for that case).
  Rewrote the paragraph: the round trip works; what still raises
  `KeyError: 'flags'` is a bare `SettingsFrame(...).pack()` with no
  enclosing packet (reproduced directly), which is an unsupported
  invocation, not a round-trip defect. Cited `FrameType.post_process`
  by name rather than the stale `httpv2.py:144` line number (the
  real raise is at `packet['flags'][name]`, confirmed by traceback).
  `GH-445` is left alone -- it is this repo's own issue shorthand,
  used throughout pcapkit/ and tests/, and #445 is in fact an issue.
- test_base_class_contract.py:45 called #547 and #570 "issues";
  both are pull requests.
- test_const_str_payload_870_unit.py:12 called #869 a "GitHub
  issue"; it is a pull request.

No behaviour or citation-style changes -- tests/** is exempt from
the #719 PR-citation rule. Ran each file individually under pytest
and plain unittest (all three use subTest): 6/6, 7/7, 60/60 passed
both ways.
@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.

1 participant