Repository navigation
Releases: auroraxo/docrot
Release list
docrot v1.8.0 — local-repo scanner + docrot-check action
Added
scan_local.py+ tests (6) — local-repo scanner for CI and GitHub
Action use. Same classification rules asscan.py(in-repo / missing /
external / unresolvable) but operates on a checked-out tree, so a CI
step can run the same engine on its own repository without a GitHub
token. Headline figure:externalThirdPartyBroken + missingInRepo.
test_scan_local.pycovers a 9-image fixture mixing dead external,
missing in-repo, and healthy refs; the live-CI path is gated by
SKIP_LIVE_CHECKS=1.- CI: dogfoods
auroraxo/docrot-check(warn-only) so the published
engine scans the engine's own docs. Pinned to the action'sv1tag
now that the tagged release exists. - README "Screened, not rot" section — explicit list of the three
in-repoREADME.mdimages that look like dead rot (a favicon that
points to a non-200, a local asset path that's only resolved by the
docs site, and a sponsor placeholder) but are actually intentional
and reproducible; documents the live host-aggregation result for
deepwiki/repology/starchartso a future reader doesn't file a
duplicate issue. - README "Known rot clusters" section — eight cluster hosts
(travis-ci.org legacy, broken.stock, dead-knight, etc.) with the
number of distinct target URLs and their live HTTP status, plus the
upstream issues filed against the affected projects.
Changed
- CI test matrix now runs
test_scan_localalongside the existing
test_docrotandtest_version_driftsuites (70 + 19 + 6 = 95 tests on
Python 3.10/3.12). docrot-checkpin in the docs CI moved from a hard-coded commit
SHA to the action's publishedv1tag.
docrot v1.7.0 — reproducibility & community trust release
Changelog: 10 commits since v1.6.0. Scanner behavior and published v8 numbers are unchanged — this release is about trust and reproducibility.
Highlights:
- 60-second reproduction section in the README: re-run a published Wave-3 finding (sml2h3/ddddocr, 26 broken external images) in one command with the committed scanner — numbers must match the dataset or "the rot moved — open an issue".
- CI: GitHub Actions workflow running the 89-test stdlib suite on Python 3.10/3.12 for push and PR, with a README badge.
- Community standards complete: MIT LICENSE, CONTRIBUTING.md, Contributor Covenant 2.1 Code of Conduct, CITATION.cff, bug/feature issue templates, SECURITY.md (private disclosure via GitHub Security Advisories).
- Report page (codebyaurora.com/docrot/) now ships canonical, Open Graph, and Twitter card metadata.
- Documentation: 300-repo v5→v8 scanner-audit section in the README; upstream outcomes updated (tensorflow#128150 fixed by merged PR tensorflow#128179 — third merged upstream fix).
Full diff: v1.6.0...main
docrot v1.6.0 — Scanner v8: two more phantom classes closed
v1.6.0 / Scanner v8: fence indent 0-7 + list-item-local pairing — two more phantom classes closed
Found during manual classification of the v7 rescan (before-publishing
rule, again): BOTH defects were phantoms inside the freshly produced v7
datasets. Nothing was published from v7.
-
airbnb/javascript 'react/hello.jpg' (wave 2): the reference lives in a
4-space-indented ```jsx fence inside a list item; GitHub renders it as
code (verified in rendered HTML) but the fence regex only stripped
indent 0-3. CommonMark allows up to 3 spaces BEFORE the list marker,
so fences inside items legitimately sit deeper -> strip 0-7. -
jujumilk3 '
' (wave 3): the code span's opener sits in one
list item, content+closer after a blank line in the next; an odd
backtick run in the first item shifted positional pairing and left the
span content live. Pairing now splits at list-item starts
(_pair_backtick_runs), still paragraph-local within items.
Schema version 7 -> 8. Suite 87 -> 89 (both real-file shapes as
regressions; the jujumilk3 fixture topology verified against GitHub
HTML: that item renders ).
Also ships tools/synthesize_v8.py: 300-repo v5->v6->v7->v8 synthesis
with hard expectation gates (E1a airbnb 0, E1b jujumilk3 2, E1c skills
0, E2 webpack 327) committed BEFORE any v8 result exists; exit 2 on
incomplete inputs, exit 3 blocks publication on red.
docrot v1.5.2 — triple-newline pairing edge closed
Residual edge in the v1.5.1 paragraph-local inline-code pairing, found while re-reviewing the fix itself: a content part starting with a single newline (triple-newline sequences) was misrouted as a blank-line separator and skipped pairing — the phantom-ref class survived in that corner (reproduced with a fixture, leaked p.png). Separator detection now requires a full blank-line match. Suite 87 green. The running 300-repo v7 rescan is being restarted under this release so the published v7 datasets carry the fully closed class.
docrot v1.5.1 — Scanner v7: phantom reference class closed
v1.5.1 — Scanner v7: CommonMark inline-code pairing
Found by the manual-verification rule, before anything was published: while classifying the wave-2/wave-3 v6 rot-set movers, anthropics/skills carried a "missing" target path from flow root — which is actually a code example in eval-hillclimb.md (``). GitHub renders it as <code> (verified against the rendered HTML); scanner v6 counted it as a broken image. Root cause: the old regex paired backtick runs positionally ((+).*?\1`); real documents interleave run lengths (stray single ticks around triple-tick literals), parity flipped mid-document, and span content survived stripping.
Fix: equal-length run pairing per CommonMark, paragraph-local — a code span never crosses a blank line. Verified against the real 68 KB file (phantom gone), the webpack README at its scanned commit (no regression; all reference-style badge defs still resolve), plus 4 new regression tests.
Honesty note: the wave-2 v6 dataset published today contains exactly this one known phantom. A 300-repo v7 rescan (all three waves) is starting now and supersedes the v6 wave datasets; the public story is not updated until that synthesis is complete and every rot-set mover is verified one by one.
Dataset schema version 6 → 7. Suite 82 → 86 green.
docrot v1.5.0 — Scanner v6: reference-style images counted
v1.5.0 — Scanner v6: reference-style images are counted
Found by a scanner-vs-API parity probe: the paid API's Markdown extractor already consumed [label]: url definitions; the open-source scanner silently skipped ![alt][label] uses — under-counting references in repos that use them (false-negative class; the mirror image of the v1.4.0 comment find).
Fix: full, collapsed, and shorthand uses resolve against their definitions. Conservative guards: link-only definitions are not images; unresolved uses produce nothing; labels case-insensitive; code/comment strips apply as before. Dataset schema version 5 → 6.
Tests: 8 new (resolve ×3, link-only exclusion, unresolved, case-fold, code-block, comment); suite 74 → 82 green.
Correction (2026-09-29, same day): this release was initially tagged on a commit where the new tests raised 8 NameErrors (unqualified extract_image_refs call; the red suite run was not heeded before shipping). Product code was unaffected and separately verified. The tag is repointed to include the test fix, the suite is verified 82/82 on the tagged commit, and the CHANGELOG carries the public correction bullet.
docrot v1.4.0 — HTML comments no longer counted as image references
v1.4.0 — HTML comments are no longer counted as image references
Fix: image-looking syntax inside <!-- ... --> comments no longer enters the reference dataset. Comment content is never rendered — the fourth false-positive family this project has closed (examples/code → entities → fenced & inline code in the API → comments).
Found by the parity ritual: the paid API (docrot-scan-api v1.3.0) strips HTML comments in all three extractors; checking scanner↔API parity pointed back at the scanner itself, which still counted them.
Implementation: strip_html_comments blanks each comment with same-length whitespace (newlines preserved), wired into extract_image_refs after strip_code.
Dataset integrity: every upstream finding in waves 1–3 was hand-verified before filing, so no report is affected; only aggregate reference counts may include a small number of commented-out images. The outcomes ledger is unchanged.
Verification: repro before (commented  flagged as reference), clean after; 2 new regression tests — suite 72 → 74 green.
docrot v1.3.1 — tier chart + mixed-basis correction
v1.3.1 — tier chart + a public correction
New: the wave-3 report section now ends with "The same finding, drawn" — an inline SVG (no JS, no external requests) comparing the three measured tiers on like-for-like metrics: rot share per 100 scanned (26% / 27% / 30%) and third-party share of unique images (53% / 31% / 57%). Building the chart is what surfaced the bug below.
Correction (the datasets were right, the prose wasn't): earlier text compared shares across different bases — README said "77% vs 29%" (external-per-unique-image vs third-party-per-reference), the field log said "77% vs 50%", and the wave-2 report section even printed the self-contradictory "77% external vs 77%". Like for like, the true story is:
- external share of unique images: 77% → 77% → 75% (flat across tiers)
- third-party share of unique images: 53% → 31% → 57% (swings with where a corpus's outside images live)
- third-party share of references: 29% → 19% → 48%
All affected sentences in README, the live report, and the field log now carry the corrected numbers with a visible correction note. Every JSON dataset was and remains correct; no number in any finding or issue was affected — this was a prose-comparison error in the project's own narrative, caught by the project's own new chart.
Tests: 72 (+3 covering the tier chart: value order, labels, absence with a single tier).
docrot v1.3.0 — Wave-3 report section, 3-tier empirical proof, and outcome receipts
What's new in v1.3.0
- Wave-3 report section (
generate_report.py): accepts an optional 6th CLI argument (wave3-results.json) and renders the companion section "A third wave: one star tier down" with its own KPIs, a 3-tier cross-wave narrative, and the per-wave findings table. - Empirical milestone: 300 repositories scanned across three tiers (top-100, ≥15k stars, 10k–15k stars). The share of repositories carrying at least one broken documentation image stays remarkably steady: 26/100 → 27/100 → 30/100. Rot is not a quirk of the absolute top of GitHub; it is an intrinsic property of documentation maintenance across star tiers.
- Upstream outcomes (18 receipts):
- sml2h3/ddddocr#317: all 26 off-repo images on author CDN
cdn.wenanzhe.comreturn HTTP 404; sponsor table and captcha demos broken in READMEs. - Azure/azure-quickstart-templates#14882: all 892 CI/deployment status badges on
azurequickstartsservice.blob.core.windows.netreturn HTTP 409PublicAccessNotPermittedacross 146 READMEs. - aalansehaiyang/technology-talk#84: author's personal docsite
offercome.cnis completely unreachable (HTTPS timeout); 477 unique off-repo images dead acrossdocs/md/**.
- sml2h3/ddddocr#317: all 26 off-repo images on author CDN
- Documentation & tests: README updated with the full wave-3 results, record-rot analysis, and the 6-argument CLI signature. Suite expanded to 69 tests (+5 covering wave-3 report rendering, cross-wave narratives, error disclosure, and HTML escaping).
- Live report: codebyaurora.com/docrot/ updated and deployed with md5 parity.
v1.2.0 — Scanner v5: HTML entity decode, corrected wave-2 dataset
Scanner v5 (237ca95)
HTML-entity-encoded <img src> attribute values were live-checked undecoded. Browsers unescape entities in attribute values before fetching, so a URL like ?v=4&s=18 renders fine in every reader — but the scanner requested the raw string and recorded HTTP 400.
Fix: decode HTML img src values only (html.unescape); markdown refs pass through unchanged. Two regression tests added; suite 60/60.
Corrected wave-2 dataset (10839f1)
Rescanned the 100-repository wave-2 corpus under v5:
- externalBroken 248 → 104
axios/axios136 → 0: the entire block was CHANGELOG contributor avatars that were never brokentrekhleb/javascript-algorithms40 → 32,rustdesk/rustdesk−1,jackfrued/Python-100-Days+1 (live drift between the two scans, verified individually)missingInRepo48 andunresolvable11 unchanged — the three filed issues (PowerToys#50821, firecrawl#4776, flutter#193415) are in-repo cases and were never affectedNousResearch/hermes-agentrecovered from the v4 transient fetch error (uniqueImages 9 → 15), validating themarkdownFetchErrorscontract
Published copy at codebyaurora.com/docrot/docrot-wave2.json replaced with md5 parity (f5c050ff774f2cab255aecba5b88456b).
The pattern
Third scanner-caused false-positive class found by auditing our own findings before publishing (after adev/ docs-site roots and silent fetch skips in v3/v4). Every headline number in this repository has now survived a "prove it is really broken" pass — and the corrections are public, not quietly patched.