#59 dogfood: switch root knip.json to production-marked config#61
Merged
Conversation
Adopt the gated knip double-run on habit-hooks itself by marking entry and project patterns with trailing `!` and listing test files as unmarked entry. The production pass now surfaces test-only / dead-code findings for clearing. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RzQYUPZUBMKMaVwMDGPJAB
knip's production pass flagged `requiresNodeRuntime` in src/wrap/resolve.ts as unused-in-production: only resolve.test.ts imported it directly, while production reaches the logic solely through `spawnTarget`. Removed the `export` (making it a private helper) and dropped the direct unit test — both branches stay covered by the existing `spawnTarget` tests, which now exercise the helper the way production does. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RzQYUPZUBMKMaVwMDGPJAB
knip's production pass flagged `fallbackNotice` in src/wrap/notices.ts as unused-in-production: only notices.test.ts imported it directly, while production reaches it through the public `noticesFor`. Removed the `export` and dropped the standalone unit test — the surviving `noticesFor` test asserts the same fallback string through the public entry point, so no coverage is lost. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RzQYUPZUBMKMaVwMDGPJAB
knip's production pass flagged `resolveFix` in src/mapper/mapper.ts as unused-in-production: only mapper.test.ts imported it directly, a back door into the module. Production reaches the logic through the public mapIssues -> resolveAction -> resolveActionFix -> resolveFix chain. Demoted it to a private function and rewrote the test block to exercise all seven fix-resolution cases through the public mapIssues entry point (via a test-local routeAs helper), preserving every case. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RzQYUPZUBMKMaVwMDGPJAB
…sBranch knip's production pass flagged `getMergeBase` in src/git/scope.ts as unused-in-production: only scope.test.ts imported it directly. Production reaches it transitively through the public `getChangedVsBranch`. Demoted it to a private helper and rewrote the test to drive through getChangedVsBranch with real branch divergence (main advanced past the branch point), so the assertion genuinely depends on correct merge-base resolution. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RzQYUPZUBMKMaVwMDGPJAB
knip's production pass flagged the `GitScopeError` export in src/git/resolve-scope.ts: the class is thrown in production (requireRepo, reached via resolveScope) but caught only by the generic Error handler in cli.ts that reads `.message` — production never references the type name. Only resolve-scope.test.ts imported the name, for a toThrow(GitScopeError) assertion. Demoted the class to module-private (still thrown) and changed the test to assert the observable message through the public resolveScope entry point. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RzQYUPZUBMKMaVwMDGPJAB
knip's production pass flagged `listPrompts` in src/prompts/registry.ts as unused-in-production: only registry.test.ts and coverage.test.ts walked the full registry; production uses point lookups via lookupPrompt. Extracted the seed catalogue (RuleSeed, supplementalSeeds, buildPrompt, and a new allSeeds()) into src/prompts/seeds.ts, which buildRegistry now consumes in production. Deleted listPrompts; tests enumerate via allSeeds() and add a check that every seed is reachable through the production lookupPrompt path. allSeeds() dedups last-wins to match the registry Map, so severities are unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RzQYUPZUBMKMaVwMDGPJAB
knip's production pass flagged `buildPresetSensors` in src/sensors/preset.ts:
a thin legacy adapter over buildDefaultSensors('typescript', ...) that no
production path reached — runner.ts -> assembleSensors calls
buildDefaultSensors directly. Only preset.test.ts used the adapter. Deleted
the adapter and its orphaned imports and retargeted the test at the real
production entry point (buildDefaultSensors), preserving the TS preset
composition assertions.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RzQYUPZUBMKMaVwMDGPJAB
…eError knip's production pass flagged both error classes in src/baseline/store.ts as unused-in-production: they are thrown in production (validateVersion, parseRaw, shape validation, all reached via loadBaseline) but their names were imported only by store.test.ts for .toThrow(<class>) identity checks. Demoted both to module-private classes (still thrown) and dropped the identity assertions; the paired message-regex assertions through loadBaseline preserve coverage and match the messages production throws. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RzQYUPZUBMKMaVwMDGPJAB
knip's production pass flagged both helpers in src/config/tool-smells.ts as
unused-in-production: production consumes only the derived consts
(JSCPD_SMELL = singleSmellFor('jscpd'), COMMENT_SMELL =
catalogueSmell('non-essential-comment')), while the functions themselves
were imported only by tool-smells.test.ts. Demoted both to module-private
(still building the consts at module load) and rewrote the tests to assert
the single-pick / identity-pick invariants through the production-consumed
consts. Retired three error-path tests that fed synthetic inputs production
never produces; the load-time guards still take the suite red on a real
catalogue regression.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RzQYUPZUBMKMaVwMDGPJAB
knip's production pass flagged both helpers in src/cli/init/install-commands.ts as unused-in-production: production reaches them only transitively via the public installCommandsFor, while the exports were imported directly only by install-commands.test.ts. Demoted both to module-private and migrated every distinct case (per-package-manager command assembly via lockfile seeding; per-tool package expansion) to run through installCommandsFor. Test-count drop is consolidation, not lost cases. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RzQYUPZUBMKMaVwMDGPJAB
knip's production pass flagged `detectLanguage` in src/cli/init/scaffold-config.ts as unused-in-production: production reaches it only transitively via the public scaffoldConfig, while the export was imported directly only by scaffold-config.test.ts. Demoted it to module-private and rewired all five detection tests (python via pyproject.toml / setup.py, typescript default, scaffold carries language, explicit override) through scaffoldConfig, asserting the written config's language. The sibling detectLanguageWithReason export (used by report-language.ts) and the pre-existing DetectedLanguage type are untouched. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RzQYUPZUBMKMaVwMDGPJAB
…umerKnipMajor knip's production pass flagged buildKnipArgs, consumerKnipMajor and resolveKnipBin in src/checks/knip-wrap.ts. They are defined in knip-resolve.ts and were re-exported from knip-wrap.ts solely so the test could import them from ./knip-wrap.js. resolveKnipBin and buildKnipArgs are genuine production-surface exports of knip-resolve.ts (knip-wrap imports and calls them), so the test now imports them directly from ./knip-resolve.js and the re-export line is gone. consumerKnipMajor was only used internally within knip-resolve.ts, so it is un-exported (private); its three version-detection edge cases (v6 omits classMembers, missing/unparseable package.json falls back to v5 and adds classMembers) are rewritten to drive through the public knipWrap.run via a consumer knip bin shim. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RzQYUPZUBMKMaVwMDGPJAB
…nternals knip's production pass flagged tryBundledJscpdBin, resolveJscpdBin and runJscpdWrap in src/checks/jscpd-wrap.ts. The real production entry is the jscpdWrap Check (consumed by sensors/registry.ts); these were exported only for tests. Mirroring the knip-wrap fix: extracted bin resolution into a new sibling module src/checks/jscpd-resolve.ts where resolveJscpdBin is a genuine production export (jscpd-wrap imports and calls it); tryBundledJscpdBin moved there and made private. runJscpdWrap is un-exported and its tests drive through jscpdWrap.run. Also removed the test-only `tmpRoot` seam from the production path; cleanup is now verified by redirecting TMPDIR and asserting the scratch dir ends empty. The -n noSymlinks invariant and arg construction are byte-identical. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RzQYUPZUBMKMaVwMDGPJAB
…apper
knip's production pass flagged src/sensors/python-preset.ts as an unused
file: production builds python sensors through the registry
(runner -> assembleSensors -> buildDefaultSensors('python') ->
DEFAULT_SENSOR_IDS.python), never through this module. python-preset.ts was
a superseded thin wrapper (issue #16 made the registry the single
construction site) whose only importer was its own test. Deleted the file
and its test; added a python-preset structural block to preset.test.ts that
asserts the sensor composition against the live buildDefaultSensors('python')
path. ruff mapping, spawn-failure, and end-to-end python coverage remain in
adapter/notices/python-acceptance tests. This also clears the pre-existing
unused PythonPresetInput type.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RzQYUPZUBMKMaVwMDGPJAB
knip flagged both exports in src/baseline/auto-prune.ts as unused (default and production passes). Both are referenced only internally by the public runWithAutoPrune (used by cli.ts and exercised by tests); no other file imported them, so the export keyword was gratuitous. Demoted both to module-private. No behaviour change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RzQYUPZUBMKMaVwMDGPJAB
knip flagged reportSkillResult in src/cli/init/reporters.ts as unused (default and production). It is called only internally by the sibling reportSkillResults (plural), which is the genuinely-used export (run.ts). Dropped the gratuitous export keyword. No behaviour change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RzQYUPZUBMKMaVwMDGPJAB
knip flagged globsFor (export) and DiscoverOptions (type) in src/discover.ts as unused (default and production). Both are referenced only internally by the public discoverFiles; no other file imports them. Dropped the export on both. discoverFiles (the real entry point) is untouched. No behaviour change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RzQYUPZUBMKMaVwMDGPJAB
knip flagged the `export type { BaselineFile }` re-export in
src/baseline/commands.ts as unused: BaselineFile is exported from store.ts
(where it is consumed across the baseline modules and runner) and nobody
imports it from commands.ts. Removed the re-export and the import that only
fed it; BaselineEntry stays (genuinely used here).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RzQYUPZUBMKMaVwMDGPJAB
knip flagged ReapResult in src/baseline/reap.ts as unused: it is only the return-type annotation of reapBaseline in the same file; no other module imports the name. Dropped the export keyword. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RzQYUPZUBMKMaVwMDGPJAB
knip flagged DetectedLanguage in src/cli/init/scaffold-config.ts as unused: it only annotates detectLanguageWithReason's return in the same file; no other module imports the name. Dropped the export keyword. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RzQYUPZUBMKMaVwMDGPJAB
knip flagged both types in src/guide/guide.ts as unused: they only annotate the guide() function's signature in the same file; no other module imports the names. Dropped the export keyword on both. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RzQYUPZUBMKMaVwMDGPJAB
knip flagged SensorFactory in src/sensors/registry.ts as unused: it is used only internally (the registry Map and sensorFactory's return type); no other module imports the name. Dropped the export keyword. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RzQYUPZUBMKMaVwMDGPJAB
knip flagged SensorRunInput in src/sensors/runner.ts as unused: it only annotates the run() method param in the same file; no other module imports the name. Dropped the export keyword. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RzQYUPZUBMKMaVwMDGPJAB
knip flagged WrapperSpec in src/sensors/wrapper-script.ts as unused: it only annotates runWrapper/wrapperScriptSensor params in the same file; no other module imports the name. Dropped the export keyword. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RzQYUPZUBMKMaVwMDGPJAB
knip flagged LeafSpec (src/sensors/leaf.ts), and the checkLeafSensor + LeafSpec re-exports plus the PresetInput type (src/sensors/preset.ts) as unused. registry.ts imports checkLeafSensor/LeafSpec directly from leaf.js, so preset.ts's re-exports of them were gratuitous; PresetInput was orphaned when buildPresetSensors was removed. Demoted LeafSpec to module-private in leaf.ts, trimmed preset.ts to only the still-consumed issueToViolation/violationToIssue re-exports, and deleted PresetInput with its now-unused imports. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RzQYUPZUBMKMaVwMDGPJAB
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adopt the gated knip double-run on habit-hooks itself by marking entry
and project patterns with trailing
!and listing test files asunmarked entry. The production pass now surfaces test-only / dead-code
findings for clearing.
Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01RzQYUPZUBMKMaVwMDGPJAB