Repository navigation
docs(conventions): 16 unresolved cross-references render as plain text, CI stays green #934
Description
docs/source/contributing/conventions.rst has 16 unresolved Sphinx cross-references. They render as plain literal text instead of links, and CI never notices because make html passes neither -W nor nitpicky — the build succeeds and the reference silently degrades.
Measured with an explicit nitpicky build (python -m sphinx -n -b html -j 4 docs/source/. <out>) plus a read of the rendered HTML, on af2324522:
| role as written | lines | why it fails |
|---|---|---|
:mod:pcapkit.corekit.sentinels`` |
165, 168, 171, 174, 261 | no API page registers that module |
:class:NoValueType`` |
197 | unqualified, no target |
:mod:aenum`` |
371, 388, 536 | aenum is not in intersphinx_mapping |
:class:~aenum.Enum, `:class:`~aenum.StrEnum |
340, 536, 701 | same |
:meth:~pcapkit.const.http.method.Method.get`` |
444 | no target |
:class:~pcapkit.const.ftp.command.FEATCode`` |
575, 716 ×2 | no target |
These split into two kinds, and the fix differs:
- The five
pcapkit.corekit.sentinelsreferences are a genuine gap. refactor(corekit): house all four sentinels in one shared module (#911) #922 created that module as the single home for all four sentinels, and nodocs/source/page documents it — so the page that defines the sentinel convention cannot link to where the sentinels live. Adding the API page fixes five of the 16 and is the highest-value part. - The six
aenumones may be working as intended —aenumis deliberately absent fromintersphinx_mapping. If that exclusion is deliberate, these should stop using:mod:/:class:roles and use plain literals instead, so the page stops claiming a link it cannot make. Worth a decision rather than an assumption. NoValueType,Method.getandFEATCode×3 look like plain misses — either the target needs qualifying or the API page needs the entry.
Surfaced while verifying #932, which introduces none of them: the nitpicky warning sets for af2324522 and #932's head are byte-identical. Filed separately rather than widening that PR.
Worth considering alongside the fix: adding -n to the docs build so a future unresolved reference fails CI instead of degrading silently. That is a bigger change than this issue and may want its own decision, given there are 1275 warnings on main today.
Metadata
Metadata
Assignees
Labels
Projects
- StatusShow more project fieldsDone
Activity
JarryShaw commentedon Sep 29, 2026
Splitting this three ways, because one part has file contention and one needs your call.
Part A — the
pcapkit.corekit.sentinelsAPI page. In flight now. A worker is adding the missing page underdocs/source/pcapkit/corekit/plus its index entry. This resolves five of the 16 (:165,:168,:171,:174,:261) without editingconventions.rstat all — the references fail because no page documents the module, so creating the page is the whole fix. That is deliberate:conventions.rstis owned by #932's branch right now and two agents editing one file lose each other's work silently.Part B — the remaining edits inside
conventions.rst. Blocked on #932.NoValueTypeat:197is unqualified andMethod.getat:444plusFEATCodeat:575/:716×2 need either qualifying or an API entry; either way the fixes land in that file. Blocked until #932 merges, at which point the contention is gone.Part C — the six
aenumroles. Needs your call.:mod:aenumat `:371`, `:388`, `:536` and `:class:`~aenum.Enum/~aenum.StrEnum`` at:340,:536,:701fail becauseaenumis absent fromintersphinx_mapping`. Two readings::mod:/:class:roles and become plain literals, so the page stops promising a link it cannot make.aenumtointersphinx_mappingfixes all six at once.I lean on (1) without knowing the history:
aenumhas no published objects.inv on its docs host that I have verified, and the otherintersphinx_mappingentries are all projects that do. But you may have excluded it for a reason I cannot see from the config, so I am not guessing.Also worth a separate decision, not filed here: adding
-nto the docs build so a future unresolved reference fails CI rather than degrading silently. There are 1275 warnings onmaintoday, so that is a project in itself.JarryShaw commentedon Sep 29, 2026
Part A is up as #936, and it turned up more than the five references — plus a trade-off worth recording.
Four additional
:mod:pcapkit.corekit.sentinels`` misses resolve as a side effect, inside the docstrings ofpcapkit/corekit/enum.py, `pcapkit/corekit/module.py` and `sentinels.py` itself. So nine of the tree's unresolved references to that module go away, not five.But the total warning count rises, 1275 → 1287. Each sentinel type is now documented in two places — its old re-export path and the new canonical page:
so pre-existing broken references inside those docstrings fire twice. Those three
autoclasslines also predate this work and cut against the house rule that docs name the real defining module rather than the re-export.A cross-review is measuring the one thing that decides whether this is acceptable: whether the duplication produces ambiguous cross-reference targets. An ambiguous
:class:NullType`` can silently resolve to the wrong page, which would be worse than the plain-text rendering #936 fixes. If it does, the fix is to make one documented home per class and drop or redirect the three shim directives.Separately, a new defect this surfaced — broken cross-references inside
pcapkit/corekit/sentinels.py's own docstrings: an unqualified__new__, a bareNullType, and aProtocolBase._lookup_next_layerattributed to the wrong class. Out of scope for #936, which was told not to touch that file. Recording them here rather than filing a fourth issue; say if you would rather they had their own.docs(corekit): add the sentinels API page so conventions.rst referenc…
JarryShaw commentedon Sep 29, 2026
My plan is for (2) but i dont think
aenumpublished any objects.inv so we cannot cross ref them anyways unfortunately.JarryShaw commentedon Sep 29, 2026
Ruling recorded, verbatim:
Your conclusion is right; the mechanism is slightly different, and the project already decided this. Measured rather than assumed:
aenumdoes publish anobjects.inv—https://aenum.readthedocs.io/en/latest/objects.invreturns200(309 bytes,# Project: aenum). But parsed with Sphinx's own loader it holds 5 objects total: 2std:doc, 3std:label, and zeropy:objects. So no:mod:,:class:or:func:reference intoaenumcan ever resolve, exactly as you expected — adding it tointersphinx_mappingwould fix none of the six and would cost an inventory fetch per build.And this was already settled and written down:
docs/source/conf.py:95-106deliberately excludesaenumwith that reasoning recorded — "do serve a realobjects.inv, but each contains onlystd:doc/std:labelentries and zeropy:objects … so no:mod:,:class:or:func:cross-reference into them could ever resolve", alongsidepyshark,pypcapandemoji, withpypcapfileexcluded for 404ing outright. The note ends by saying those packages are referenced as plain external links instead.So option (2) is not available, and option (1) is already project policy — the six
aenumroles inconventions.rstare violating a rule the config states explicitly. The fix is to convert them to plain literals or external links, matchingconf.py's own instruction.needs: decisionremoved — part C is decided. It joins part B as blocked on the same thing: every remaining fix lands inconventions.rst, which #932 owns until it merges. Part A (#936) is alreadyreview: good-to-goand independent of that file.docs(corekit): add the sentinels API page so conventions.rst referenc…
JarryShaw commentedon Sep 30, 2026
Unblocked — #932 merged as
382375811, so this can start. Holding it behind one other item, deliberately.docs/source/contributing/conventions.rstis wanted by three issues at once: #937 (adding the sentinel object-naming rule the SCREAMING_SNAKE ruling needs), #918 (harvesting the settled design rulings), and #934 parts B and C (the remaining unresolved-reference fixes). Two agents editing one file lose each other's work with no error — the later write simply wins — so these go one at a time rather than in parallel.#937 has the file first and exclusively, scoped to the
.. _sentinel-convention:section and the sentinel table only, and briefed not to reflow or tidy anything else so the next edit does not collide with unrelated churn. This issue starts the moment #937's PR is up.Nothing else blocks it. Recording the order so it is checkable rather than remembered.
JarryShaw commentedon Sep 30, 2026
Correcting my own blocker condition. I wrote that this starts "the moment #937's PR is up". That PR is now up as #939 (
8c5feda9c, +343/-214 across 24 files) — but the condition I stated was wrong.docs/source/contributing/conventions.rststays contended until #939 merges, not until it opens. A worker starting here now would branch from382375811and edit the same file #939 already rewrites, producing a merge conflict on a 24-file rename rather than a clean apply. Nothing is lost either way, but unpicking that costs more than waiting.So the real condition is: starts when #939 merges. Checkable with
gh pr view 939 -R JarryShaw/PyPCAPKit --json state,mergedAt. #939 isreview: pendingwith a cross-review in flight on a different model from its author.Recording the correction rather than quietly keeping this blocked past a condition I had already declared satisfied.
docs(conventions,const): resolve part B's unresolved cross-references (…
docs(conventions,const): resolve part B's unresolved cross-references (…
JarryShaw commentedon Sep 30, 2026
Closing: all 16 are resolved on
main, re-counted rather than assumed. #941 merged as9ea0d6a5a(squashed), on top of #936 which landed the sentinels API page.Re-measured at
9ea0d6a5aagainst this issue's own table::mod:/:class:namingaenumaenum'sobjects.invcarries zeropy:objects, so no role could ever have resolved:class:NoValueType``~pcapkit.corekit.sentinels.NoValueType:meth:…Method.get``:class:…FEATCode``docs/source/pcapkit/const/ftp.rstnow carriesautoclass:: pcapkit.const.ftp.command.FEATCode:mod:pcapkit.corekit.sentinels``docs/source/pcapkit/corekit/sentinels.rstexists (#936)A seventeenth appeared mid-flight and is also fixed: #940 deleted
FastBindingAcknowledgmentStatus.getoutright, so its:meth:role stopped resolving between the filing and the fix. Now a plain literal atconventions.rst:459, role count 0.Two things this issue raised that are deliberately not closed with it, so they are not lost:
-nin the docs build, so a future unresolved reference fails CI rather than degrading silently. Still worth doing and still its own decision — there are ~1275 warnings onmain, so it cannot simply be switched on.aenumexclusion is now pinned by a test rather than resting on prose:tests/project/test_conventions_doc_claims.py::AenumRoleExclusionTestsfails if anyaenumrole is reintroduced.docs(sphinx): add opt-in issue, pr and discussion roles, and convert …