You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
design: #514 recorded two rulings it never implemented — the Base/public collapse and the enforcing @final #778
#514 closed with "nothing added" — the maintainer ruled the custom-versus-builtin registration check is not wanted. But two substantial rulings were recorded on it before it closed, neither implemented and neither tracked anywhere now that it is shut. This issue exists so they are not lost.
(b) Collapse each XXXBase/public pair, and make name-registration opt-in by keyword. Five pairs: Protocol/ProtocolBase, Engine/EngineBase, Reassembly/ReassemblyBase, TraceFlow/TraceFlowBase, and the Schema pair. Blast radius measured on #514: ≈390 edit points, five PRs. Three hazards no issubclass sweep finds, all verified there:
tests/test_base_class_contract.py:75-80 imports both halves of all five pairs, so it does not fail — it fails to import. A rewrite or a deletion, and it is the one file every family touches.
tests/_support.py:337 defines a fakeclass ProtocolBase and injects it into sys.modules['pcapkit.protocols.protocol'] at :354, consumed via protochain.py:72,158. Rename the real one and the fake stops being found; tests/test_support_helpers.py:413 then AttributeErrors.
The split is today a runtime-enforced final substitute: ProtocolBase.__init_subclass__ rejects the registration keyword, so a library-style subclass cannot opt in at all. Collapsing to one class downgrades that guarantee to "do not pass the keyword".
The enforcing @final. Recorded ruling: subclassing a FINAL class raises rather than warns, in Info.__init_subclass__ (corekit/infoclass.py:244) and Schema.__init_subclass__ (protocols/schema/schema.py:1065); re-decorating an already-FINAL class raises too. Key it on __finalised__ == FINAL in the class's own__dict__, not a new flag — getattr is wrong because typing.final's __final__ inherits, so every descendant reads final. Measured additive: Info 486 descendants / 453 FINAL / 0 subclassed; Schema 445 / 408 / 0.
These are one decision, not two. (b) is safe with the runtime @final and lossy without it, because the @final is what replaces the guarantee the collapse removes.
Also blocks #682 — the registry is keyed on __name__.upper() (foundation/registry/protocols.py:219), so a user class named HTTP still displaces the built-in, and two distinct HTTP classes are already live in the ProtocolBase descendant tree. Opt-in-by-keyword registration makes that displacement explicit instead of automatic, which is the cheapest available fix for #682.
Needed from the maintainer
Did closing #514 with "nothing added" drop (b) and the @final enforcement as well, or only the custom-versus-builtin check? The rulings above read as decided in principle, but they were recorded on an issue that then closed with nothing added, so I will not start ≈390 edit points on that reading. One of:
Both still wanted — I sequence them together as one programme, five PRs, @final first so the collapse is not lossy.
#514 closed with "nothing added" — the maintainer ruled the custom-versus-builtin registration check is not wanted. But two substantial rulings were recorded on it before it closed, neither implemented and neither tracked anywhere now that it is shut. This issue exists so they are not lost.
(b) Collapse each
XXXBase/public pair, and make name-registration opt-in by keyword. Five pairs:Protocol/ProtocolBase,Engine/EngineBase,Reassembly/ReassemblyBase,TraceFlow/TraceFlowBase, and theSchemapair. Blast radius measured on #514: ≈390 edit points, five PRs. Three hazards noissubclasssweep finds, all verified there:tests/test_base_class_contract.py:75-80imports both halves of all five pairs, so it does not fail — it fails to import. A rewrite or a deletion, and it is the one file every family touches.tests/_support.py:337defines a fakeclass ProtocolBaseand injects it intosys.modules['pcapkit.protocols.protocol']at:354, consumed viaprotochain.py:72,158. Rename the real one and the fake stops being found;tests/test_support_helpers.py:413thenAttributeErrors.finalsubstitute:ProtocolBase.__init_subclass__rejects the registration keyword, so a library-style subclass cannot opt in at all. Collapsing to one class downgrades that guarantee to "do not pass the keyword".The enforcing
@final. Recorded ruling: subclassing aFINALclass raises rather than warns, inInfo.__init_subclass__(corekit/infoclass.py:244) andSchema.__init_subclass__(protocols/schema/schema.py:1065); re-decorating an already-FINALclass raises too. Key it on__finalised__ == FINALin the class's own__dict__, not a new flag —getattris wrong becausetyping.final's__final__inherits, so every descendant reads final. Measured additive:Info486 descendants / 453FINAL/ 0 subclassed;Schema445 / 408 / 0.These are one decision, not two. (b) is safe with the runtime
@finaland lossy without it, because the@finalis what replaces the guarantee the collapse removes.Also blocks #682 — the registry is keyed on
__name__.upper()(foundation/registry/protocols.py:219), so a user class namedHTTPstill displaces the built-in, and two distinctHTTPclasses are already live in theProtocolBasedescendant tree. Opt-in-by-keyword registration makes that displacement explicit instead of automatic, which is the cheapest available fix for #682.Needed from the maintainer
Did closing #514 with "nothing added" drop (b) and the
@finalenforcement as well, or only the custom-versus-builtin check? The rulings above read as decided in principle, but they were recorded on an issue that then closed with nothing added, so I will not start ≈390 edit points on that reading. One of:@finalfirst so the collapse is not lossy.@finalenforcement only — cheap, additive, 0 in-tree breakage, and it does not touch the public API. register_protocol's key space is still not unique: the three HTTP classes share one key (follow-up to #675) #682 then stays open on its own merits.__name__.upper()displacement as accepted residual risk.Nothing else is blocked on the answer, so this is a quiet hold rather than a stall.