chore(deadcode): fix dead-code ratchet — remove unused devDeps + rebaseline knip (#607) - #673
chore(deadcode): fix dead-code ratchet — remove unused devDeps + rebaseline knip (#607)#673scottschreckengaust wants to merge 2 commits into
Conversation
…seline knip (#607) The dead-code ratchet (scripts/check-deadcode-ratchet.mjs) failed on main: knip counted 91 issues vs the committed baseline of 78 in knip-baseline.json, so `node scripts/check-deadcode-ratchet.mjs` exited 1. (The issue reported 81; main has drifted further since it was filed.) The +13 came from three devDependency findings plus pre-existing unused exports/types. Resolved all three devDep findings knip reported: - Removed @types/pdf-parse from cdk/package.json — genuinely dead. pdf-parse@2 ships its own types (dist/pdf-parse/cjs/index.d.cts) and cdk already has a local ambient declaration cdk/src/types/pdf-parse.d.ts; the @types stub was the stale v1 API. cdk tsc compile stays green after removal. - Removed @astrojs/check from the root package.json — a duplicate of the docs workspace's own dependency (docs/package.json), which is where `astro check` actually runs (docs:check script, docs-astro-check pre-commit hook). Root's copy was unused; astro check stays green (0 errors) after removal. - Suppressed markdown-link-check in knip.json (docs ignoreDependencies) — a knip FALSE POSITIVE, not dead code. It is invoked via ./node_modules/.bin/markdown-link-check inside docs/scripts/link-check.sh (wired into the //docs:link-check mise task), which knip cannot parse. Per the ratchet's own guidance, false positives belong in knip.json, not the baseline. Rebaselined knip-baseline.json count 78 -> 88 to the honest post-cleanup count (empirically measured, not inflated to paper over the failure). The remaining 88 are pre-existing unused exports/types and the jira-forge-app fixture files, out of scope for #607. The ratchet is advisory/non-blocking in CI today but now exits 0. Closes #607 Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
✅ Acceptance summary (for the reviewer)#607 —
🔀 Merge guidance (for the reviewer)Independent — no ordering constraint. Cluster 🤖 orchestrator note (agent) — promotion is orchestrator-driven; merge remains a human action. |
theagenticguy
left a comment
There was a problem hiding this comment.
Reviewed by cloning the repo, checking out the head, and reproducing every claim rather than trusting the description. The core of this PR is right, and the description is unusually honest about its own numbers. I verified the arithmetic independently and it holds exactly.
Confirmed:
kniponorigin/main= 91, on this branch = 88. Each of the three edits removes exactly one finding, so91 - 3 = 88is measured, not padded to make the gate pass. The CI job log agrees:Dead-code count holding at baseline (88).- The drift is genuine code drift, not a tooling artifact. I ran
mainunder both knip6.20.0and the currently pinned6.23.0and got 91 under each, so the+13is real and the version bump in #522 did not cause it. @types/pdf-parseremoval is safe. That package tops out at v1.1.5 (the v1 API) against an installedpdf-parse@2.4.5, which ships its owndist/pdf-parse/cjs/index.d.cts.@astrojs/checkroot removal is safe, and the hoisting worry dissolves on inspection:docs/node_modules/.bin/astro-checkis already a symlink up into rootnode_modules, anddocs/package.jsonstill declares the identical^0.9.9range, so yarn v1 keeps hoisting it and the retained lock entry is legitimate.markdown-link-checkis a true false positive.docs/scripts/link-check.shinvokes./node_modules/.bin/markdown-link-check, wired through//docs:link-checkintodrift-preventionintomise run build. TheignoreDependenciesentry sits in the correct workspace scope, since the dep is declared indocs/package.json.- The
yarn.lockedit is minimal and correct. Nothing else requested@types/pdf-parse.
Re-greening an advisory gate that was already red on main is the right call, and rebaselining to the measured value instead of an inflated one is the right instinct. Two things should change first.
1. The baseline absorbs 3 findings that your own rule says belong in knip.json (should-fix). The three files findings under integrations/jira-forge-app/ are live Forge app source, not fixtures. Putting "integrations/**" in knip's ignore drops the count to 85, which I verified by running it. 85 is the honest number, and 88 bakes 3 phantom findings into durable state that every future ratchet PR inherits.
2. The new comment blesses an ambient type declaration that misdescribes the runtime, and there is a live bug behind it (should-fix, pre-existing). Details inline on cdk/package.json. Not introduced by this PR, so I am not asking you to fix it here, only to stop citing it as justification and to file it.
Nits, both pre-existing and neither blocking: scripts/check-deadcode-ratchet.mjs:52 still documents "the installed knip (6.20.0, pinned exactly)" while the pin is now 6.23.0, worth correcting while you are in this file. And the roughly 7 genuine unused export/type regressions inside the +13 merged unnoticed precisely because this job is continue-on-error: true. They deserve a tracking issue, otherwise the "flips to blocking once the baseline is driven to zero" milestone recedes with every merge.
Requesting changes narrowly, on the one-line knip.json change plus the comment corrections. Everything else here is sound and I would happily approve once the baseline reads 85.
| "entry": ["astro.config.mjs", "src/content.config.ts", "src/components/**/*.astro"], | ||
| "project": ["src/**/*.{astro,ts,tsx}"], | ||
| "ignoreDependencies": ["@astrojs/check", "remark-gfm", "@pagefind/default-ui", "jest"] | ||
| "ignoreDependencies": ["@astrojs/check", "markdown-link-check", "remark-gfm", "@pagefind/default-ui", "jest"] |
There was a problem hiding this comment.
The markdown-link-check addition here is correct and well-justified. The gap is what is not here.
knip-baseline.json calls the 3 remaining files findings "the jira-forge-app fixture files," but they are live application source:
integrations/jira-forge-app/manifest.yml:10declareshandler: index.handler, sosrc/index.jsis the Forge function entry point.src/index.js:22imports./proxy.js.test/proxy.test.jsruns undermise //:test:jira-forge-app, which is a dependency ofmise run build.
knip flags all three only because integrations/ is not in the root workspaces array (cdk, cli, docs) and is not in knip's ignore, so nothing there is reachable from a configured entry point. That is the textbook definition of the per-category false positive this file's own guidance says to suppress here rather than absorb into the baseline.
I verified the fix. Adding "integrations/**" to the top-level ignore:
"ignore": [
".semgrep/**",
"scripts/**",
"integrations/**"
]drops the count from 88 to 85, with files going to 0 and only the pre-existing exports: 44 / types: 41 remaining. A scoped knip workspace entry for the Forge app would work too and is arguably better, since it would keep real dead code there detectable instead of blanket-ignoring the directory.
Worth doing rather than deferring: the baseline is the durable artifact every future dead-code PR ratchets against, so 3 phantom findings embedded now are 3 that can never be cleaned up, and they push the "driven to zero" flip-to-blocking milestone permanently out of reach.
There was a problem hiding this comment.
Done — but as a scoped knip workspace entry rather than a blanket integrations/** ignore (the option you flagged as arguably better). knip.json now declares integrations/jira-forge-app with entry: ["src/index.js!", "test/**/*.test.js"] and project: ["src/**/*.js"], so the Forge function entry point and its tests are reachable and any real dead code there stays detectable instead of being blanket-ignored.
Verified locally: files findings → 0, count drops 88 → 85 (exports: 44 / types: 41 remaining), and node scripts/check-deadcode-ratchet.mjs → ✅ Dead-code count holding at baseline (85). exit 0. Fixed in e825a75.
| "@types/jest": "^30.0.0", | ||
| "@types/js-yaml": "^4.0.9", | ||
| "@types/node": "^26", | ||
| "@types/pdf-parse": "^1.1.5", |
There was a problem hiding this comment.
Removing this is correct, and safe for a slightly different reason than the description gives. cdk/tsconfig.json sets "types": ["node"], which already blocked @types/pdf-parse from being auto-included, and the local declare module 'pdf-parse' in cdk/src/types/pdf-parse.d.ts shadows node_modules/@types on explicit import anyway. So this devDep was already inert and its removal is a genuine no-op. Good call either way, since a v1 type stub against an installed v2 is a trap.
The problem is the justification recorded in knip-baseline.json, which describes the removal as "superseded by pdf-parse@2's bundled types plus the local cdk/src/types/pdf-parse.d.ts ambient declaration." Those two are not complementary. The ambient declaration overrides v2's real bundled types, and it describes the v1 API:
function pdfParse(data: Buffer, options?: { max?: number }): Promise<PdfParseResult>;
export = pdfParse;pdf-parse@2.4.5 exports no callable default. Verified against the installed package:
$ node -e "const m=require('pdf-parse'); console.log(Object.keys(m)); console.log(typeof m.default)"
[ 'AbortException', ..., 'PDFParse', 'VerbosityLevel', 'getException' ]
undefined
So in cdk/src/handlers/shared/attachment-screening.ts:258, pdfParseFn = (mod as any).default ?? mod resolves to the module namespace object, and the call at line 277 throws TypeError: pdfParseFn is not a function. It is caught and rewrapped, so every application/pdf attachment reaching line 201 fails as PDF "<name>" could not be processed. It may be corrupt or use unsupported features. PDF attachment screening is broken for all inputs, and the failure is indistinguishable from a genuinely corrupt PDF.
The { virtual: true } mock at cdk/test/handlers/shared/attachment-screening.test.ts:365 supplies { __esModule: true, default: jest.fn() }, so the suite asserts against a v1 shape that no longer exists and cannot catch this.
This predates the PR: pdf-parse@^2.4.5 and the ambient decl landed together in #434 (2026-06-30), and the as any plus the ambient override is what kept tsc quiet. I am not asking you to fix it here. Two smaller asks:
- Drop the "plus the local ambient declaration" clause from the baseline comment, so this PR does not turn a version-mismatched stub into documented policy.
- File a follow-up. The v2 shape is
new PDFParse({ data: content }).getText()returning aTextResult, and fixing it means deleting the ambient decl, letting v2's own types apply, and replacing the mock with something that reflects the real module.
There was a problem hiding this comment.
Thanks — reproduced the v2-shape mismatch independently (require('pdf-parse') exports PDFParse/VerbosityLevel/… and .default is undefined, so (mod as any).default ?? mod yields the namespace object and the call throws TypeError). Both asks done:
- Dropped the "plus the local ambient declaration" clause from
knip-baseline.jsonso this PR no longer cites the version-mismatched stub as justification. - Filed the follow-up: fix(cdk): PDF attachment screening broken — ambient pdf-parse decl describes v1 API against installed v2 #683 — captures the v1-decl-over-v2 root cause, the silent "could not be processed" symptom for every PDF, the v1-shaped virtual mock that hides it, and the fix (delete the ambient decl, adopt the v2
new PDFParse({ data }).getText()API, and add a real-PDF end-to-end test so a future mismatch fails loudly).
Fixed in e825a75.
| { | ||
| "count": 78, | ||
| "comment": "Dead-code ratchet baseline for issue #282 (cairn MVG gate #6). This is the knip issue count at the time the gate was introduced — pre-existing unused exports/types that are out of scope to remove in the gate PR. The ratchet (scripts/check-deadcode-ratchet.mjs) fails the build only if the count rises above this number. When dead code is removed and the count drops, lower this value in the same PR to lock in the gain. Per-category false positives belong in knip.json, not here." | ||
| "count": 88, |
There was a problem hiding this comment.
Per the knip.json comment, this should read 85 once the integrations/** findings move to knip.json where this file's own guidance puts them. I verified 85 by running the ratchet with that change applied.
Two accuracy fixes for the prose on line 3 as well:
- "the jira-forge-app fixture files" is wrong.
src/index.jsis the Forge function entry point named inmanifest.yml, andtest/proxy.test.jsruns inmise run build. Calling live source "fixtures" is what makes absorbing them into the baseline look reasonable. - The
@types/pdf-parseclause credits the local ambient declaration as part of why removal is safe. It is the opposite: that declaration shadows v2's real types and currently misdescribes the runtime. See thecdk/package.jsonthread.
Separately, this comment is now carrying the full changelog of one PR. The baseline is machine-read for count only, so consider trimming the narrative to a sentence and letting the PR and issue history hold the reasoning, otherwise the next three dead-code PRs each append a paragraph and the actual rule at the top gets buried.
There was a problem hiding this comment.
All three addressed in e825a75:
- Count → 85. Achieved by the scoped
integrations/jira-forge-appknip workspace entry (see theknip.jsonthread), not by absorbing the findings. Ratchet now reads✅ Dead-code count holding at baseline (85). - "fixture files" wording removed. The comment no longer mischaracterizes the Forge source; the
filesfindings are gone from the count entirely now that the app is a proper workspace. - "plus the local ambient declaration" clause removed (the pdf-parse v2 bug is filed as fix(cdk): PDF attachment screening broken — ambient pdf-parse decl describes v1 API against installed v2 #683).
- Narrative trimmed. The comment is back to the durable rule plus a one-line note that the remaining 85 are pre-existing
exports (44)+types (41), tracked in chore(deadcode): ratchet down the 85 pre-existing unused exports/types (follow-up to #607) #682 — no per-PR changelog accreting in a machine-read file.
…88→85 (#607) Addresses review on #673: - Add a scoped knip workspace entry for integrations/jira-forge-app (entry: src/index.js from manifest handler + test/**/*.test.js) instead of absorbing its 3 live-source `files` findings into the baseline. Keeps real dead code in the Forge app detectable rather than blanket-ignoring the directory. Drops the count from 88 to the honest 85. - Rebaseline knip-baseline.json count 88→85 and trim the comment to the durable rule; the remaining 85 are pre-existing exports (44) + types (41), tracked in #682. Drops the inaccurate "fixture files" wording and the "plus the local ambient declaration" clause (the pdf-parse v2 runtime bug behind it is filed as #683). - Correct the stale "knip (6.20.0)" pin comment to 6.23.0 in the ratchet. Ratchet: `node scripts/check-deadcode-ratchet.mjs` → holding at baseline (85), exit 0.
|
@theagenticguy — all review feedback addressed in e825a75. Thanks for the thorough, reproduce-everything review. Blocking (both resolved):
Nits + follow-ups:
Baseline now reads 85. Re-requesting review once checks are green. |
Summary
The dead-code ratchet (
scripts/check-deadcode-ratchet.mjs) was failing onmain, independent of any PR. This re-greens it by removing 2 genuinely-dead devDependencies, suppressing 1 knip false positive, and rebaselining the knip issue count to its honest post-cleanup value.Closes #607
Reproduced root cause + evidence
On a fresh
origin/mainworktree:The knip count is now 91 vs baseline 78 (the issue reported 81;
mainhas drifted further since it was filed). Category breakdown of the 91:devDependenciesfilesexportstypesThe 3
devDependenciesfindings are the ones this issue targets:@astrojs/check(rootpackage.json),markdown-link-check(docs/package.json),@types/pdf-parse(cdk/package.json).The fix
I confirmed each candidate against knip and its actual usage before acting — the issue's premise that all three are "genuinely dead" holds for two of them; the third is a knip false positive.
@types/pdf-parsefromcdk/package.json— genuinely dead.pdf-parse@2.4.5ships its own types (dist/pdf-parse/cjs/index.d.cts) and cdk already carries a local ambient declarationcdk/src/types/pdf-parse.d.ts. The@typesstub was the stale v1 API (^1.1.5) against an installed v2. Nothing references it.mise //cdk:compile(tsc) stays green after removal.@astrojs/checkfrom the rootpackage.json— a duplicate of thedocsworkspace's own dependency.docs/package.jsondeclares@astrojs/checkas adependency, and that is whereastro checkruns (thedocs:checkscript and thedocs-astro-checkpre-commit hook, bothcd docs && ./node_modules/.bin/astro check). The root devDep was unused.mise //docs:checkstays green (0 errors, 0 warnings) after removal; the hoisted install is retained via the docs dependency.markdown-link-checkinknip.json(docsignoreDependencies) — a knip false positive, not dead code. It is invoked via./node_modules/.bin/markdown-link-checkinsidedocs/scripts/link-check.sh(wired into the//docs:link-checkmise task, itself part ofdrift-prevention), which knip cannot parse. Per the ratchet's own documented guidance ("Per-category false positives belong in knip.json, not here") and the issue's option 2, this is suppressed rather than removed.mise //docs:link-checkstill resolves and runs the binary.Rebaselined
knip-baseline.jsoncount78 → 88— the honest, empirically-measured post-cleanup count (91 − 2 removed − 1 suppressed = 88), not inflated to paper over the failure. The remaining 88 are pre-existing unused exports/types plus the jira-forge-app fixture files, out of scope for #607 (see Follow-ups).Note: this ratchet is advisory / non-blocking in CI today (
check:deadcode-ratchet— "Advisory in CI for now; flips to blocking once the baseline is driven to zero"), but it now exits 0 as the issue requires.Testing
node scripts/check-deadcode-ratchet.mjs→✅ Dead-code count holding at baseline (88).exit 0 (the acceptance criterion).mise //cdk:compile→ exit 0 (proves@types/pdf-parseremoval doesn't break cdk typecheck).mise //docs:check(astro check) → 0 errors / 0 warnings / 0 hints (proves@astrojs/checkroot removal is safe).mise //docs:link-check→ runs, links checked (provesmarkdown-link-checkstill available).pre-commit run --files <changed>→ all Passed / correctly Skipped.origin/main..HEAD) → no leaks.mise run build: the only failure is a pre-existing environment limitation in this sandbox —cdk:synth:quieterrors onec2:DescribeAvailabilityZones(the assumed IAM role lacks EC2 AZ-lookup permission). It is an AWS auth error, not a dep/type regression: handler esbuild bundling (including--external:pdf-parse) completes with noCannot find module/ TS errors. Unrelated to this change.Files changed
package.json— drop root@astrojs/checkdevDepcdk/package.json— drop@types/pdf-parsedevDepknip.json— addmarkdown-link-checkto docsignoreDependencies(false-positive suppression)knip-baseline.json— count78 → 88+ documented reasoningyarn.lock— 7-line removal (@types/pdf-parseentry only)Dependencies / related
Follow-ups (noted, not touched — out of scope for #607)
exports+ 41 unusedtypesflagged by knip — pre-existing drift; risky to remove without per-symbol analysis. Should be chipped away in future dead-code PRs, ratcheting the baseline down each time.filesunderintegrations/jira-forge-app/(src/index.js,src/proxy.js,test/proxy.test.js) — flagged as unused by knip; likely a Forge-app entry-point that knip's config doesn't recognize as an entry. Worth a scopedknip.jsonentry or removal in a dedicated PR.🤖 Generated with Claude Code