Skip to content

Autophagy cleanup: drop one unused JSDoc type import (sole mechanically-dead construct in the tree) - #682

Open
philcunliffe wants to merge 1 commit into
masterfrom
autophagy/cleanup-2026-08-08
Open

Autophagy cleanup: drop one unused JSDoc type import (sole mechanically-dead construct in the tree)#682
philcunliffe wants to merge 1 commit into
masterfrom
autophagy/cleanup-2026-08-08

Conversation

@philcunliffe

Copy link
Copy Markdown
Contributor

Autophagy cleanup tick. A full-tree mechanical dead-code sweep over 732 JS files turned up exactly one trim. Everything else that the scans flagged was verified reachable and left byte-identical.

Gate on this branch: npm test 3849 pass / 0 fail / 6 skipped, npm run typecheck clean. Both identical to the pre-change baseline measured on the same tree.


Trim 1 (the only one): unused @import { ChildProcess, SpawnOptions }

src/core/cli/wizard/sync_now.js line 17. Residue of the wizard integration in 4fb95dc.

- * @import { ChildProcess, SpawnOptions } from 'node:child_process'

Reachability searches

Both names occur exactly once in the file, on the @import line itself, and nowhere else in the repo in a way that binds to this file's JSDoc scope. A JSDoc @import is file-local, so the only binding site that matters is this file:

$ grep -n "ChildProcess\|SpawnOptions" src/core/cli/wizard/sync_now.js
17: * @import { ChildProcess, SpawnOptions } from 'node:child_process'

That is the sole occurrence: no type annotation, no cast, no @param, no @returns uses either name.

Whole-tree scan for unused JSDoc type imports across src/, hypaware-core/, bin/, test/, scripts/ reported this as the only file with an unused @import name:

$ node find_unused_type_imports.mjs .
src/core/cli/wizard/sync_now.js	ChildProcess, SpawnOptions
files with unused @import types: 1

Checklist

  • No importer anywhere: a JSDoc @import binds names only inside its own file; nothing outside can consume it.
  • No test reference: the two names never appear in test/.
  • No @ref LLP attached to it: the module docblock's @ref LLP 0203#offer [implements] sits on line 15 and annotates the module's purpose, not the type import. It is untouched by this diff.
  • Not a package entry point: sync_now.js is not in package.json main/exports/bin, and this is a comment line regardless.
  • Not a CLI surface: no command name, subcommand, or flag.
  • Not a documented public API: neither name appears in README.md, docs/, or CONTEXT.md.
  • No dynamic/string-keyed reachability: type-only JSDoc names are erased at runtime and cannot be reached by string key.
  • Typecheck proves it: tsc -p tsconfig.json --noEmit (checkJs: true, strictNullChecks: true) passes with the line removed. The remaining @import { RunWizardSyncNowOptions, WizardSyncNowResult } is still used and is kept.

Considered and deliberately NOT trimmed

Recorded so the negative result is auditable too.

44 exports with no consumer outside their own file

A scan for exported names with zero references anywhere else in the tree (searching .js/.ts/.json/.md across src/, hypaware-core/, bin/, test/, scripts/, docs/, llp/, notes-archive/ and the root files, matching the bare name so string literals and manifest keys count) returned 44 names. Every single one is used inside its own file, so none is dead. Examples:

mapFinishReason  hypaware-core/plugins-workspace/ai-gateway/src/message_projector.js
  688:  const finishReason = mapFinishReason(stringValue(ctx.message.stop_reason))
  837: export function mapFinishReason(stopReason) {

OAUTH_TOKEN_URL  hypaware-core/plugins-workspace/claude-account/src/oauth.js
   17: export const OAUTH_TOKEN_URL = 'https://platform.claude.com/v1/oauth/token'
  142:   const res = await doFetch(OAUTH_TOKEN_URL, {

These are over-exported, not dead. Narrowing an export is a refactor with real blast radius (files: ["src/", ...] publishes the whole tree, so consumers can deep-import), and is out of scope for an autophagy tick.

267 files no other file mentions by name

All are convention-discovered entry points, confirmed by reading the discovery code:

  • test/**/*.test.js (231 files): scripts/run-tests.js walks directories and picks up anything ending .test.js.
    61:    entries = fs.readdirSync(dir, { withFileTypes: true })
    73:    if (entry.isFile() && entry.name.endsWith('.test.js')) {
    
  • hypaware-core/smoke/flows/*.js (36 files): loaded by dynamic import() from a string name.
    31:  const flowsDir = path.resolve(import.meta.dirname, '..', 'flows')
    32:  const flowPath = path.join(flowsDir, `${name}.js`)
    58:  const mod = await import(flowUrl)
    

No orphan module exists under src/ or any plugin src/.

2 statements after a return

Both are hoisted async function walk(dir) declarations placed below the return, and both are called before it, so they are reachable by hoisting and deliberate style.

  • src/core/cache/partition.js:169 - await walk(root) on line 168, above the return results.
  • src/core/cache/spool.js:411 - await walk(root) on line 410, above the return tables.

0 unused runtime imports

A scan of every import ... from clause (default, namespace, and named) across src/, hypaware-core/, bin/, test/, scripts/ found no import whose binding is unused in its file. Empty output.

0 unused module-level declarations

A scan for top-level non-exported function/const/let/var/class declarations never referenced again in their own file, cross-checked against the whole tree for string-key reachability, returned nothing.

0 commented-out code blocks

A scan for runs of 2+ consecutive // lines whose bodies look like code returned 30 hits, and all 30 are genuine explanatory prose that the heuristic mis-flagged on backticked identifiers and trailing punctuation. Many carry @ref LLP annotations (src/core/cli/wizard/index.js, src/core/commands/clients.js, src/core/config/action_reconciler.js, and others). Nothing commented out.

7 barrel re-exports with no consumer beyond the barrel

src/core/observability/index.js   buildResource                      from ./resource.js
src/core/usage-policy/index.js    PATH_CANONICALIZE_ERROR_KIND       from ./canonical.js
src/core/usage-policy/index.js    PATH_ALIAS_PROBE_ERROR_KIND        from ./fold.js
src/core/usage-policy/index.js    CLIENT_SYNC_LIST_VERSION           from ./client_sync.js
src/core/usage-policy/index.js    FOLDER_ASK_VERSION                 from ./folder_ask.js
src/core/usage-policy/index.js    FOLDER_ASK_UNREADABLE_ERROR_KIND   from ./folder_ask.js
src/core/util/index.js            MAX_LABEL_CHARS                    from ./json_util.js

All left in place:

  • src/core/observability/index.js and src/core/util/index.js are published package.json entry points (./core/observability, ./core/util), and buildResource additionally reaches the . / ./core entry via export * from './observability/index.js' in src/core/index.js:8. Explicitly excluded by the "not a package entry point" rule.
  • src/core/usage-policy/index.js is the subsystem façade, and files: ["src/", ...] publishes it. These are the subsystem's error-kind and version vocabulary, i.e. deliberate interface, not dead code.

Trimming a barrel's public surface is an API decision for a human, not a mechanical autophagy trim.

Neither name is referenced anywhere in the file; both occur only on the
`@import` line itself. Residue of the wizard integration in 4fb95dc.

The module's `@ref LLP 0203#offer` annotation and the still-used
`RunWizardSyncNowOptions` / `WizardSyncNowResult` import are untouched.

npm test (3849 pass, 0 fail) and npm run typecheck are unchanged from the
pre-change baseline on the same tree.

Co-Authored-By: Claude <noreply@anthropic.com>
@philcunliffe

Copy link
Copy Markdown
Contributor Author

Review round: CLEAN

Verdict: clean. No findings at any severity. This is a one-line deletion of a JSDoc comment line, and it is correct. Recommend a human dispose of it as-is.

Reviewed head SHA 579c5c3806de677f1e8e9f8c1cd7fd6ac6695637, branch autophagy/cleanup-2026-08-08. Reviewed in a detached worktree at the branch head; the main checkout was not touched. PR left as a draft, unlabelled, unmerged.

What the diff actually contains

I checked the branch as it stands now rather than trusting the claim, and the head has not advanced past the single-trim commit:

$ git rev-list --count origin/master..origin/autophagy/cleanup-2026-08-08
1
$ git rev-list --count origin/autophagy/cleanup-2026-08-08..origin/master
0
$ git diff --numstat origin/master origin/autophagy/cleanup-2026-08-08
0	1	src/core/cli/wizard/sync_now.js

One commit, one file, zero insertions, one deletion:

- * @import { ChildProcess, SpawnOptions } from 'node:child_process'

git diff --check is clean (no whitespace damage). Nothing else in the tree moved.

Independent confirmation of the deadness claim: CONFIRMED

I re-ran the reachability work from scratch rather than reading the PR body's version of it.

1. Whole-tree bare-name grep (catches string-literal and manifest-key reachability, not just the import graph), against origin/master so the pre-deletion state is the search space:

$ git grep -n -E 'ChildProcess|SpawnOptions' origin/master -- .
src/core/cli/wizard/first_ask.js:15: * @import { ChildProcess, SpawnOptions } from 'node:child_process'
src/core/cli/wizard/first_ask.js:247: *   spawnFn?: (command, args, options: SpawnOptions) => ChildProcess,
src/core/cli/wizard/sync_now.js:17: * @import { ChildProcess, SpawnOptions } from 'node:child_process'
src/core/cli/wizard/types.d.ts:1:import type { ChildProcess, SpawnOptions } from 'node:child_process'
src/core/cli/wizard/types.d.ts:579:  spawnFn?: (...) => ChildProcess
src/core/cli/wizard/types.d.ts:608:  spawnFn?: (...) => ChildProcess
test/core/remote-open-browser.test.js:11: * ChildProcess (an EventEmitter with `unref`).

Seven occurrences in four files. In sync_now.js the two names occur exactly once, on the deleted line itself. Every other occurrence lives in a different file that carries its own binding (first_ask.js has its own @import; types.d.ts has its own import type on line 1; the test hit is prose in a comment). A JSDoc @import is file-local, so those other files are unaffected by this deletion, and none of them is touched by the diff.

2. The subtle trap, checked explicitly. sync_now.js really does spawn a child (import { spawn } from 'node:child_process' on line 20, opts.spawnFn ?? spawn on line 180, child.on('error', ...) on line 191), so a careless reader could assume the type import is load-bearing. It is not: spawnFn and the child are typed through RunWizardSyncNowOptions, which is declared in types.d.ts, and types.d.ts resolves ChildProcess/SpawnOptions through its own line-1 import type. No annotation in sync_now.js names either type: I grepped every @param, @returns, and /** @type */ cast in the file and none references them.

3. Positive control, the strongest evidence here. Grep proves absence of the string; it does not prove tsc was actually resolving these names. So I proved the detector works: on the post-deletion branch head I temporarily added @param {SpawnOptions} [probe] to a function in the file and re-ran typecheck:

src/core/cli/wizard/sync_now.js(132,12): error TS2304: Cannot find name 'SpawnOptions'.

checkJs does resolve JSDoc type names in this file and does hard-fail on an unresolved one. Since the branch typechecks clean with the import gone, there is provably no surviving use of either name in the file. I reverted the probe; the worktree is byte-identical to the branch head.

4. Checklist, each item verified rather than assumed:

  • No importer: a JSDoc @import binds names only inside its own file. Nothing outside can consume it, by construction.
  • No test reference: neither name appears anywhere in test/ except the unrelated prose comment above.
  • No @ref LLP attached: the module's @ref LLP 0203#offer [implements] sits on line 15, separated from the @import block by a * blank line, which per CLAUDE.md breaks attachment. It annotates the module, not the import. It survives intact on line 15, verified in the committed blob.
  • Not a package entry point: package.json bin is bin/hypaware.js only; exports lists ., ./core, ./core/observability, ./core/sinks, ./core/query, ./core/util, ./integration, ./tui. sync_now.js is in none of them, and a comment line could not be an entry point regardless.
  • Not a CLI surface / not a documented public API: zero hits for either name across docs/, llp/, and README.md.
  • No dynamic or string-keyed reachability: JSDoc type names are erased before runtime; there is no runtime value to reach by string key. The module itself is genuinely live (src/core/cli/wizard/index.js:35 imports runWizardSyncNow, and test/core/cli/wizard/sync_now.test.js covers it), but the module is not being removed, only this comment line.
  • Neighbouring import undisturbed: the still-used @import { RunWizardSyncNowOptions, WizardSyncNowResult } from '../../../../src/core/cli/wizard/types.js' is present and unchanged on line 17, root-anchored .js specifier intact.

Scope discipline: CLEAN

Zero insertions across the whole diff, so there is no room for style churn. No reformatting, renames, refactors, reordering, or comment rewording. The change is exactly one mechanically dead line. The PR body's "considered and deliberately not trimmed" section is correctly a negative record only: none of those 44 exports, 267 convention-discovered files, 7 barrel re-exports, or 2 post-return hoisted declarations appears in the diff, which is the right call. I confirmed the two post-return walk declarations are indeed reachable by hoisting (src/core/cache/partition.js calls walk(root) before the return, same in spool.js), so leaving them alone was correct and not a missed trim.

Gates, run by me on the branch head

gate result
npm test 3849 pass / 0 fail / 6 skipped, 3855 total, exit 0
npm run typecheck (tsc -p tsconfig.json --noEmit) clean, exit 0
npm run build:types (tsconfig.build.json, the published declaration build) clean, exit 0
gh pr checks 682 all 9 pass (test 22/24, typecheck 22/24, duplicate-numbers)

npm install was used rather than npm ci (no tracked lockfile). I ran build:types on top of the required gates because the repo's root-anchored type-import convention exists to keep the published types/ tree resolvable, and an @import edit is exactly the kind of change that could break it. It does not.

Branch is 1 ahead / 0 behind origin/master, so it merges without a rebase.

A one-line diff deserves a plain answer: this is correct, minimal, and in scope. Nothing to fix, and I am deliberately not proposing further cleanups, since scope creep is itself against the autophagy brief.

@philcunliffe
philcunliffe marked this pull request as ready for review August 8, 2026 03:39
@philcunliffe philcunliffe added the neutral:approved neutral reviewed this and holds it for a maintainer merge (own or adopted PR; LLP 0025/0030) label Aug 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

neutral:approved neutral reviewed this and holds it for a maintainer merge (own or adopted PR; LLP 0025/0030)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant