I kept finding the same thing in old codebases: a comment saying "workaround until X is fixed" — where X was fixed years ago. The issue is closed, the browser is dead, the version floor moved. The reason died; the code stayed.
ContextDebt is a scanner for exactly that. npx contextdebt on any repo. Zero dependencies, runs locally, your code never leaves your machine — by default the only network call is a GitHub API lookup for issue numbers it found in your own comments.
The report has three parts. First, scale: 1,813 of the most-starred repositories on GitHub, 201 million lines, 25,546 self-admitted workarounds. The median project carries fewer than one per 10,000 lines and a quarter contain none at all — which I think is the more worrying number, because a large old codebase with zero markers isn't clean, it's unlabelled.
Second, the individual cases, verified by hand. 25 comments named a date and missed it; I read all 25 and split them three ways — 14 are real deadlines a team set for itself (grafana has been able to remove something "after ~2017-06-01" for nine years), 10 are author-stamped dates where the date is a signature rather than a promise, and 1 I threw out as a false positive. All three groups are on the page, including the one I rejected.
Third, the part I added last. Every workaround that links an issue is a promise with an address on it, so I asked all of them: the corpus cites 978 distinct issues, and 679 were closed as fixed, a median of 4.2 years ago. The oldest is a knockout.js comment about Internet Explorer 7 citing an issue closed in September 2011 — and Magento 2 ships a bundled copy of that file, so the sentence is sitting in store checkouts today. Doing that pass naively gave me 752. 73 of those were pull requests nobody merged or issues closed as "not planned", which fixed nothing and in the second case make the workaround permanent rather than expired. They're excluded, and the page says so.
Six PRs came out of the same work so far:
- sentry's Node SDK carried two notes saying "remove once we drop Node X"; the floor moved to 20.19 in July and the notes stayed
- axios still sniffs the UA for Internet Explorer in same-origin checks (IE died 2022)
- video.js parses the UA for IE on every load, into a deprecated variable nothing reads
- celery declares a dependency that can never install under its own Python floor
- llama-index has version gates below its floor, with the linter warning silenced by a noqa
- vllm ships ~380 lines of Inductor monkeypatches gated on torch 2.9, a version none of its own pins install
One is merged: sentry-javascript #24183. It started as a question, not a patch — I opened issue #24182 at 13:50 UTC saying two notes read "once we drop Node X" and that had already happened; the PR went up 23 minutes later and was merged 46 minutes after that. The whole thing took 70 minutes. The other five are open, the oldest 26 days, most with no human reply — the ordinary fate of an unsolicited patch to a large project, and I would rather state it than imply a hit rate I don't have. Separately, an issue I opened on mobx (#4707) — asking whether a 2020 NoInfer hack could go now that TypeScript ships one — was answered with the fact I didn't have (MobX already requires TS 5.6) and fixed by the maintainer the next morning (#4710). Both things that moved started as a question, in a repository that was actively shipping.
To be clear about the split: the report was scanned with 0.1.7, which found the self-admitted markers and the dated ones and checked the issues they cite. The version-floor cases above — celery's uninstallable dependency, the torch gates — I verified by hand against each repo's own metadata at the time. That pattern is a detector now, as of 0.1.12: the scanner reads a manifest floor and compares it against what the comment itself claims was fixed. The report's numbers are still the 0.1.7 numbers, dated as such, because re-running the census to make them prettier is exactly the thing this report is about.
Two things it deliberately does NOT do: it never says "safe to delete" (the reason is dead — the deletion call is yours), and a closed issue is never enough on its own; the fix has to be in the version your lockfile actually resolves.
Happy to answer anything, including where it's wrong.
I kept finding the same thing in old codebases: a comment saying "workaround until X is fixed" — where X was fixed years ago. The issue is closed, the browser is dead, the version floor moved. The reason died; the code stayed.
ContextDebt is a scanner for exactly that. npx contextdebt on any repo. Zero dependencies, runs locally, your code never leaves your machine — by default the only network call is a GitHub API lookup for issue numbers it found in your own comments.
The report has three parts. First, scale: 1,813 of the most-starred repositories on GitHub, 201 million lines, 25,546 self-admitted workarounds. The median project carries fewer than one per 10,000 lines and a quarter contain none at all — which I think is the more worrying number, because a large old codebase with zero markers isn't clean, it's unlabelled.
Second, the individual cases, verified by hand. 25 comments named a date and missed it; I read all 25 and split them three ways — 14 are real deadlines a team set for itself (grafana has been able to remove something "after ~2017-06-01" for nine years), 10 are author-stamped dates where the date is a signature rather than a promise, and 1 I threw out as a false positive. All three groups are on the page, including the one I rejected.
Third, the part I added last. Every workaround that links an issue is a promise with an address on it, so I asked all of them: the corpus cites 978 distinct issues, and 679 were closed as fixed, a median of 4.2 years ago. The oldest is a knockout.js comment about Internet Explorer 7 citing an issue closed in September 2011 — and Magento 2 ships a bundled copy of that file, so the sentence is sitting in store checkouts today. Doing that pass naively gave me 752. 73 of those were pull requests nobody merged or issues closed as "not planned", which fixed nothing and in the second case make the workaround permanent rather than expired. They're excluded, and the page says so.
Six PRs came out of the same work so far:
- sentry's Node SDK carried two notes saying "remove once we drop Node X"; the floor moved to 20.19 in July and the notes stayed
- axios still sniffs the UA for Internet Explorer in same-origin checks (IE died 2022)
- video.js parses the UA for IE on every load, into a deprecated variable nothing reads
- celery declares a dependency that can never install under its own Python floor
- llama-index has version gates below its floor, with the linter warning silenced by a noqa
- vllm ships ~380 lines of Inductor monkeypatches gated on torch 2.9, a version none of its own pins install
One is merged: sentry-javascript #24183. It started as a question, not a patch — I opened issue #24182 at 13:50 UTC saying two notes read "once we drop Node X" and that had already happened; the PR went up 23 minutes later and was merged 46 minutes after that. The whole thing took 70 minutes. The other five are open, the oldest 26 days, most with no human reply — the ordinary fate of an unsolicited patch to a large project, and I would rather state it than imply a hit rate I don't have. Separately, an issue I opened on mobx (#4707) — asking whether a 2020 NoInfer hack could go now that TypeScript ships one — was answered with the fact I didn't have (MobX already requires TS 5.6) and fixed by the maintainer the next morning (#4710). Both things that moved started as a question, in a repository that was actively shipping.
To be clear about the split: the report was scanned with 0.1.7, which found the self-admitted markers and the dated ones and checked the issues they cite. The version-floor cases above — celery's uninstallable dependency, the torch gates — I verified by hand against each repo's own metadata at the time. That pattern is a detector now, as of 0.1.12: the scanner reads a manifest floor and compares it against what the comment itself claims was fixed. The report's numbers are still the 0.1.7 numbers, dated as such, because re-running the census to make them prettier is exactly the thing this report is about.
Two things it deliberately does NOT do: it never says "safe to delete" (the reason is dead — the deletion call is yours), and a closed issue is never enough on its own; the fix has to be in the version your lockfile actually resolves.
Happy to answer anything, including where it's wrong.