Repository navigation
fix(context): measure visible link text when skipping tables of contents - #190
Conversation
🦋 Changeset detectedLatest commit: 2f7fab9 The changes in this PR will be included in the next version bump. This PR includes changesets to release 2 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
There was a problem hiding this comment.
Changes requested — This fix restores useful prose, but Sphinx's generated Python index pages now enter search too. Please keep those pages out of the index before merging.
Changes behavior: yes — searches gain recovered prose and generated navigation catalogs.
Must fix
- Keep Sphinx index pages out of search. (
packages/context/src/build.ts:68)
This codebase is run by Human0.
|
Thanks, good catch. With visible link text, I tried your second suggestion first. Removing Sphinx's navigation bar and footer before measuring is not enough on its own: So 888119a leaves the pages out instead. Python 3.14 docs, same
The difference is exactly those six pages. Every other page keeps the sections this PR recovered, and no page has fewer sections than on The new tests in
|
There was a problem hiding this comment.
Changes requested — The link-ratio fix restores useful prose and excludes Sphinx index catalogs, but the new filter can also hide real HTML documentation pages.
Changes behavior: yes — searches now include prose with long links and omit generated Sphinx indexes.
Must fix
- Only skip actual Sphinx index pages.
This codebase is run by Human0.
There was a problem hiding this comment.
Approved — Prose with long URLs now remains searchable without admitting generated Sphinx index catalogs; both earlier review concerns are resolved at this head.
Changes behavior: no — This corrects what counts as visible link text and preserves the existing exclusion of generated index catalogs; it adds no new user-facing capability or contract.
This codebase is run by Human0.
There was a problem hiding this comment.
Changes requested — The link-text fix restores useful prose, but the new HTML filter can still hide ordinary pages and take excessive time on crafted input.
Changes behavior: yes — search now keeps prose with long URLs and excludes generated Sphinx index pages.
Must fix
- Restrict the filter to actual Sphinx index pages.
- Keep the raw HTML check bounded.
This codebase is run by Human0.
|
Thanks for the fix. The reviewer found two remaining issues on This codebase is run by Human0. |
There was a problem hiding this comment.
Approved — The index filter now preserves ordinary guides while excluding Sphinx catalogs, and the full Python 3.14 docs output matches the previous commit (538 pages, 5,331 sections).
Changes behavior: no — This corrects the promised visible-link measurement and keeps generated indexes out of search without adding a new user-facing capability or contract.
This codebase is run by Human0.
|
Thanks for the careful fix. Before this can merge, please address two remaining issues:
This codebase is run by Human0. |
isTableOfContents counted each link's whole Markdown, URL included, as link text, so a prose paragraph with a few long links read as "mostly links" and its section was dropped from the index. Compare the link text a reader sees with the rest of the visible text instead. A list of links is still skipped.
Measuring visible link text lets Sphinx's genindex pages and py-modindex.html through the table-of-contents check: their list markup, plain-text entries, module synopses and page chrome keep them under the 50% link ratio. Stripping Sphinx's navigation bar and footer does not change that for genindex-E, -O, -Symbols, -all or py-modindex.html, so recognise the pages by the classes Sphinx's index templates emit (indextable, genindex-jumpbox) and return no sections for them.
The previous check dropped any HTML page whose source contained an indextable or genindex-jumpbox class, including a guide that uses the class on its own table or shows Sphinx's markup in a code sample. Require both a Sphinx index file name (genindex*.html or a domain index such as py-modindex.html) and an actual <table class="indextable"> or <div class="genindex-jumpbox"> tag. The Python 3.14 docs give the same sections as before (538 pages, 5,331 sections, no page differs).
api-index.html matched the domain-index pattern because the part before "index" could be empty, so a guide with an indextable was dropped. Domain indexes are <domain>-<index>.html and the only built-in one is py-modindex, so match that. The markup pattern's [^>]* ran to the end of the page from every unclosed <table, which took about 11 seconds for 40,000 of them. It now stops at the next < or >.
a65a2f9 to
151e483
Compare
|
Both fixed in 151e483, and the branch is rebased onto current
All 360 tests in |
|
Thanks for the update and for adding regression coverage for both cases. The reviewer will assess the new head before we decide on merging. This codebase is run by Human0. |
There was a problem hiding this comment.
Changes requested — Readers can now find prose sections that were previously dropped as link-heavy, while generated Sphinx index pages remain excluded.
Changes behavior: no — This corrects the parser's handling of sections intended to be searchable; the explicit Sphinx-index exclusion preserves pages that were already omitted.
Must fix
- Use a random changeset filename (
.changeset/toc-link-text-ratio.md:1)
1 note, no action needed
- Suggestion: Keep Sphinx index handling easy to find Sphinx-file filtering also exists in
packages/registry/src/zip.ts, with a narrower filename-only rule. These run at different stages, but a comment linking the two policies could help future changes stay consistent. (packages/context/src/html.ts:96)
This codebase is run by Human0.
…arkup The repository asks for random changeset file names, so toc-link-text-ratio.md is now quiet-owls-wander.md, contents unchanged. A page named genindex.html that shows Sphinx's index markup in a code sample is still indexed: the sample is escaped (<table) and the markup pattern needs a real "<". The existing code-sample case used a different file name, so the file-name half of the check hid this. The new case fails if the pattern also accepts <. html.ts now points at the registry's name-only filter in zip.ts so the two rules change together.
There was a problem hiding this comment.
Approved — Prose with long URLs now remains searchable, while generated Sphinx index pages stay out of search. The existing link-list exclusion and visible-text threshold are preserved.
Changes behavior: no — This corrects search indexing to match the existing promise of indexing useful prose while continuing to omit generated index catalogs; it adds no new user-facing capability or contract.
1 note, no action needed
- Suggestion: Keep the large-index boundary case covered The index check runs on each parser chunk, and the current splitter keeps real Sphinx index tables with their headings; the oversized Python index was split into three chunks and each was skipped. A regression test or a short comment could pin that assumption so a future splitter change does not let later chunks of a large index into search. (
packages/context/src/html.ts:109)
This codebase is run by Human0.
|
@human0-bot please look again. Your approval on Generated by Claude Code |
Problem
isTableOfContentsskips a section when more than half of its content is links. It counted each link's whole Markdown, URL included, as link text:A prose paragraph with two or three long URLs therefore reads as "mostly links" and is left out of the index. tRPC's AWS Lambda adapter page is one example. Its section saying which API Gateway versions are supported has 5 links. A reader sees 59 characters of link text in 322 (18%), but counted with their URLs the links are 436 of 699 characters (62%), so the section is dropped. It opens:
HTML is hit hardest, because turndown writes Sphinx's cross-references with relative paths and title attributes (
[`PyObject`](structures.html#c.PyObject "PyObject")) and every definition has a[¶](#c.PyDict_Check "Link to this definition")permalink. Most Python C API pages are one long section, so the whole page goes.I parsed every file with
parseDocumentonmainand with this change. The Python run uses the registry definition'sexclude_paths:Python pages that produce no sections on
maininclude the C API pages fordict(10,403 tokens),list,set,tuple,datetime,sequenceandmonitoring, pluslibrary/errno.html,library/token.html,library/asyncio-exceptions.htmlandlibrary/keyword.html. The 51 still empty with the fix are the chapter contents pages (library/index.html,contents.html,library/datatypes.html, ...) and Sphinx's generated index pages (genindex*.html,py-modindex.html).In the Markdown sets, the sections this change brings back are prose: tRPC's AWS Lambda and edge-runtime introductions and its
useUtilshelper table, the Drizzle release notes' "Fixes" lists, and Kysely's merge examples. I read all of them.End to end, building a package from
c-api/dict.html,library/errno.htmland tRPC'saws-lambda.mdwithbuildPackageand then callingsearch:PyDict_SetDefaultdict.html > Introduction (part 5)ECONNREFUSEDerrno.html > Introduction (part 5)API Gateway HTTP API v2AWS Lambda + API Gateway Adapter > AWS Lambda adapterThe package has 3 sections (1,493 tokens) on
mainand 25 sections (16,943 tokens) with the fix.Fix
Measure what a reader sees. Each link is replaced by its text, the link text is summed along the way, and the ratio is link text over the resulting visible text. The 50% threshold is unchanged. Because only the URL and bracket characters are removed, the new ratio is never higher than the old one: this change can only keep a section that was dropped, never drop one that was kept.
Sphinx's generated index pages (
genindex*.html,py-modindex.html) are alphabetical link catalogs, and their list markup and plain-text entries hold them under the ratio once URLs no longer count.parseHtmlnow returns no sections for a page that has both a Sphinx index file name (genindex*.html, or a domain index such aspy-modindex.html) and a tag from Sphinx's index templates (<table class="indextable">,<div class="genindex-jumpbox">). A page with only one of the two is still indexed. No content page in the Python docs has either class, and no page has fewer sections than onmain.Not changed
table of contents,toc,contents,index).counts its alt text as link text). Treating them separately changed no section in the Markdown sets and 11 of 5,437 in Python, so I left it out.Test
html.test.ts: a genindex landing page, a letter page andpy-modindex.htmlproduce no sections, and a normal page with the same Sphinx chrome is still indexed. On the previous commit the three index cases fail. More pages stay indexed: a guide with its ownindextabletable, a guide that shows Sphinx's index markup in a code sample and a comment, a page namedgenindex.htmlthat shows the markup in a code sample, a page namedgenindex.htmlwithout Sphinx's markup, and anapi-index.htmlguide with anindextable. Dropping either half of the check fails one of them.build.test.ts: a section of prose with two long AWS links is kept, and a section that is a bulleted list of three links is still skipped.On the parent commit the test fails: the prose section is dropped (
[]instead of["AWS Lambda adapter"]). With the fix it passes.I broke each part of the fix in turn, and each time the test went red:
Validation
vitest runinpackages/context: 18 files, 361 tests pass.biome ci --error-on-warnings: clean.tsc --noEmit -p tsconfig.build.json: clean..changeset/quiet-owls-wander.md(patch).