Skip to content

Cleanup: drop five Phase 0 placeholder modules and unreferenced imports - #408

Merged
philcunliffe merged 1 commit into
masterfrom
autophagy/cleanup-2026-07-27
Jul 27, 2026
Merged

Cleanup: drop five Phase 0 placeholder modules and unreferenced imports#408
philcunliffe merged 1 commit into
masterfrom
autophagy/cleanup-2026-07-27

Conversation

@philcunliffe

Copy link
Copy Markdown
Contributor

Mechanically dead code only. Every trim below is backed by a tree-wide search
that came back empty. Nothing here changes behavior, formatting, or naming.

Method

Three independent detectors, then a manual reachability check on each survivor:

  1. A module-graph pass that resolves every relative specifier in every .js
    and .ts file under src/, hypaware-core/, bin/, test/, scripts/
    (including dynamic import() and JSDoc @import specifiers) and reports
    files no specifier ever targets.
  2. tsc -p tsconfig.json --noEmit --noUnusedLocals for unused imports and
    unused local bindings.
  3. tsc -p tsconfig.json --noEmit --allowUnreachableCode false for statements
    after return/throw. It reported nothing, so no unreachable code is
    removed here.

Every candidate was then re-checked by hand against: importers anywhere in the
tree, test references, @ref LLP annotations, package.json
main/exports/bin, CLI verbs reachable from bin/, prose references in
README.md / CONTEXT.md / AGENTS.md / llp/ / docs/ / notes-archive/
/ SKILL.md, and string-keyed dispatch (each symbol was searched as a bare
string, not only as an identifier). There is exactly one package.json in this
repo; the plugin workspaces under hypaware-core/plugins-workspace/ are
manifest-driven (hypaware.plugin.json), and every dynamic import() in the
tree uses either a literal specifier or a manifest-derived plugin entrypoint,
never a computed core path.


1. Five Phase 0 skeleton placeholder modules (10 files)

Deleted:

file contents
src/core/registry/config.js (6 lines) comment + export {}
src/core/registry/config.d.ts (17 lines) pure export type { ... } from '../../../hypaware-plugin-kernel-types.d.ts'
src/core/registry/queries.js (6 lines) comment + export {}
src/core/registry/queries.d.ts (16 lines) pure type re-export
src/core/registry/skills.js (6 lines) comment + export {}
src/core/registry/skills.d.ts (6 lines) pure type re-export
src/core/runtime/permissions.js (6 lines) comment + export {}
src/core/runtime/permissions.d.ts (4 lines) pure type re-export
src/core/runtime/plugin_module.js (7 lines) comment + export {}
src/core/runtime/plugin_module.d.ts (7 lines) pure type re-export

Each .js file's entire body is a stale comment plus export {}. Example:

// @ts-check

// Phase 0 skeleton placeholder. Config-section registration and
// validation land in Phase 2. Contract in config.d.ts.

export {}

They date to 5016eae feat(core): observability skeleton + core_boot_noop smoke (hy-83a). The work they reserve a slot for landed elsewhere long
ago. The config registry is createConfigRegistry in
src/core/config/schema.js, the dataset/query registry is
src/core/registry/datasets.js, the skills registry is wired through
ctx.skills from the kernel runtime, and plugin activation lives in
src/core/runtime/loader.js + src/core/runtime/activation.js. The .d.ts
siblings only re-export types that every real consumer already imports directly
from the root kernel contract, hypaware-plugin-kernel-types.js.

Searches, all empty (run from the worktree root, over the whole tracked tree):

git grep -n -F "registry/config"     -- .   # 0 hits
git grep -n -F "registry/queries"    -- .   # 0 hits
git grep -n -F "registry/skills"     -- .   # 0 hits
git grep -n -F "runtime/permissions" -- .   # 0 hits
git grep -n -F "plugin_module"       -- .   # 0 hits
git grep -n -F "queries.js" -F "skills.js" -F "permissions.js" -- .   # 0 hits
grep -rn "@ref" <all ten files>             # 0 hits

The module-graph pass independently confirms all ten files are targeted by zero
import specifiers. The only other files it flagged as untargeted are legitimate
entry points: bin/hypaware.js, hypaware-core/smoke/index.js, the
package.json exports subpaths (src/core/index.js,
src/core/query/index.js, src/core/sinks/index.js, ...), and each plugin's
manifest main (hypaware-core/plugins-workspace/*/src/index.js) - none of
which are touched.

None of the ten paths appear in package.json main/exports/bin (the
exports map lists ., ./core, ./core/observability, ./core/sinks,
./core/query, ./core/util, ./integration, ./tui, and an exports map
blocks unlisted deep subpath imports for published consumers). None appear in
any LLP document, README.md, CONTEXT.md, AGENTS.md, docs/,
notes-archive/, or any SKILL.md.

Note for the reviewer: the .d.ts halves are the more debatable half of
this trim. They are also zero-importer, and a .d.ts with no sibling .js is
stranger than neither, so they go together. If you would rather keep the type
barrels, dropping the five .d.ts files from this PR leaves the rest intact.

2. Unused imports

All confirmed by tsc --noUnusedLocals (TS6133) and by a grep -w showing
the name occurs exactly once in its file, on the import line itself.

file:line removed
src/core/cache/migrate.js:13 import { datasetsRoot } from './paths.js'
src/core/cache/retention.js:18 import { datasetsRoot } from './paths.js'
src/core/commands/status.js:3 import path from 'node:path'
src/core/daemon/status.js:3 import fs from 'node:fs'
src/core/remote/credentials.js:6 import process from 'node:process'
src/core/runtime/boot.js:24 defaultBundledWorkspaceDir from the ./bundled.js import list
hypaware-core/plugins-workspace/claude/src/projector.js:34 defaultSessionContextFile from the ./session_context.js import list
hypaware-core/smoke/flows/otel_loopback_capture.js:8 Attr from the observability import list
test/core/cache-iceberg-schema-evolution.test.js:11 import fsSync from 'node:fs'
test/core/sink-materialize.test.js:8 import fs from 'node:fs/promises'
test/core/streaming-reader.test.js:10 BATCH_BYTE_LIMIT from the streaming-reader.js import list
test/plugins/iceberg-commit.test.js:8 import { Readable } from 'node:stream'

Why safe:

  • Eight are whole-statement removals (./paths.js twice, plus node:path,
    node:fs twice, node:process, node:fs/promises, and node:stream).
    src/core/cache/paths.js has no top-level side effects (it is
    import path from 'node:path', one private const, and three pure exported
    functions), and the Node builtins have none either, so dropping the statement
    cannot change evaluation order or behavior.
  • The other four remove a single name from an import list whose remaining names
    are still used, so the module itself is still imported.
  • No JSDoc @import was orphaned. In particular src/core/daemon/status.js
    still carries @import { Dirent } from 'node:fs' on its own line, which is a
    separate declaration from the deleted value import and is untouched.
  • Nothing is removed at any definition site. Every name above stays exported and
    keeps at least one live reference; only the unused import site goes away.
    datasetsRoot is still imported by src/core/cache/maintenance.js,
    src/core/cache/partition.js, and src/core/sinks/watermarks.js;
    defaultSessionContextFile by plugins-workspace/claude/src/index.js and two
    tests; Attr by many kernel modules. defaultBundledWorkspaceDir and
    BATCH_BYTE_LIMIT stay exported and are still referenced inside their own
    defining modules (src/core/runtime/bundled.js:123 and
    src/core/cache/streaming-reader.js:74).

3. Unused local constants

file:line removed
hypaware-core/smoke/flows/local_parquet_export.js:15 const HERE = path.dirname(fileURLToPath(import.meta.url))
test/core/cli/tui/runtime.test.js:15 const ENV = { NO_COLOR: '1' }

grep -w HERE and grep -w ENV each return exactly one hit in their file: the
declaration. Both flagged by TS6133. Removing HERE orphans
fileURLToPath, which was imported solely for that line, so
import { fileURLToPath } from 'node:url' goes with it; path is still used
11 times in that flow and stays. local_parquet_export is a release-checklist
smoke and it still passes (see below).

4. Two exported constructs with zero references anywhere

src/core/cache/spool.js:18-19 - DEFAULT_FLUSH_ROW_CHUNK_SIZE

/** @deprecated Superseded by streaming reader batch limits. */
export const DEFAULT_FLUSH_ROW_CHUNK_SIZE = 1000

git grep -n -w DEFAULT_FLUSH_ROW_CHUNK_SIZE -- . returns exactly one hit in
the whole repository: this definition. Not referenced in its own file, no test,
no smoke, no @ref, no prose. Not reachable by a published consumer either:
src/core/cache/spool.js is not in the package.json exports map and an
exports map blocks unlisted deep imports. Its own JSDoc records that the
streaming-reader batch limits (BATCH_ROW_LIMIT / BATCH_BYTE_LIMIT in
src/core/cache/streaming-reader.js) replaced it.

src/core/observability/tracer.js:73-76 - getActiveProvider

/** @returns {object} */
export function getActiveProvider() {
  return trace.getTracerProvider()
}

git grep -n -w getActiveProvider -- . returns exactly one hit: this
definition. Critically, it is not part of the public observability surface:
src/core/observability/index.js re-exports by explicit name
(getTracer, getLogger, getMeter, withSpan, runRoot, buildAttrs,
Attr, context, ROOT_CONTEXT, SpanStatusCode, getActiveSpan, ...) and
getActiveProvider is absent from that list, so the export * in
src/core/index.js (which backs both the . and ./core/observability
package entry points) never picks it up. The trace import it used is still
needed by getTracer on the line above and stays. No @ref, no test, no
smoke, no prose reference.


Considered and deliberately NOT trimmed

Recording these so the sweep is auditable, and because "unreferenced" alone was
not enough to make them unarguable:

  • stopLaunchAgent (src/core/daemon/macos.js:357) and stopSystemdUnit
    (src/core/daemon/linux.js:286)
    - both have zero references tree-wide
    (hyp daemon stop goes through the PID-file path in
    src/core/daemon/runtime.js, not through launchctl/systemctl). But they are
    members of a symmetric platform-adapter lifecycle family
    (install/uninstall/start/stop/restart/status/isInstalled) that
    src/core/daemon/install.js dispatches over per platform. The right fix may
    be to add the missing stopServiceDaemon wrapper rather than delete the
    halves, so this is a design question, not a mechanical one.
  • getGascityRuntime
    (hypaware-core/plugins-workspace/gascity/src/runtime.js:35)
    - zero
    references; setGascityRuntime and requireGascityRuntime are both used.
    Deleting one third of a deliberate set/get/require accessor trio is an API
    judgment call.
  • 97 unused JSDoc @import type names flagged by TS6196 across the tree.
    Real, but touching them is a wide, low-value diff over documentation-shaped
    code, and each one needs care not to break a neighbouring name on the same
    @import line. Left alone.
  • test/core/remote-login-command.test.js:444 - an unused err binding in
    a destructure of a test helper's return value. The binding also documents the
    helper's shape; not worth the churn.
  • Exports that are unused outside their defining file but used inside it
    (64 of them). Only the export keyword is redundant there, and
    removing an export is an API change, not a deletion.

Verification

Run in the worktree, before and after, on the same machine.

npm test

tests pass fail skipped
baseline (39bc895) 2666 2657 8 1
this branch 2666 2657 8 1

Identical. All 8 failures are the known pre-existing ones in
test/core/leave-command.test.js, with byte-identical test names before and
after:

not ok 778 - leave after join removes the seed and reports the server
not ok 779 - leave clears an applied central slot, not just the seed
not ok 780 - leave reverses org-driven attaches and drops the forward identity
not ok 782 - leave after join also warns about a local central sink that keeps forwarding
not ok 783 - leave is idempotent: a second leave is the not-connected no-op
not ok 784 - leave still tears down when only a stale attach marker survives a prior partial leave
not ok 785 - leave removes the assets its attach marker records, and leaves manual copies alone
not ok 786 - leave self-heals an org attach whose plugin is gone: drops the marker, warns, stays clean

test/core/leave-command.test.js is the only failing file in both runs. No new
failures, no newly passing tests, no change in the skip count.

npm run typecheck - clean, exit 0, before and after.

Smokes for the two touched flows - both green:

smoke otel_loopback_capture: ok
smoke local_parquet_export: ok

Diffstat: 26 files changed, 1 insertion(+), 106 deletions(-). The single
insertion is the rewritten import { installObservability } ... line in
otel_loopback_capture.js after dropping Attr from its list.

No em dashes introduced (a U+2014 scan of git diff HEAD is empty), no
semicolons added, no reformatting, no renames, no reordering.

Generated by neutral's code-cleanup initiative (LLP 0036). Proposed, not asserted: every trim above is a claim to check, not a fact to trust.

Mechanically dead code only, proven unreachable by tree-wide search.

- Delete five Phase 0 skeleton placeholder module pairs whose real
  implementations landed elsewhere; nothing in the tree imports them.
- Remove unused value imports and unused local constants (corroborated
  by `tsc --noUnusedLocals`).
- Remove two exported constructs with zero references anywhere in the
  tree, including inside their own file.

No behavior change. Tests and typecheck match the pre-change baseline.

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

Copy link
Copy Markdown
Contributor Author

Fan-in check on this PR re-derived the reachability claims independently, and they hold: the five deleted .js files are empty export {} bodies, the paired .d.ts are pure export type re-exports from hypaware-plugin-kernel-types.d.ts (which stays), git grep finds zero references to any of the five module paths anywhere in the tree including llp/ and every package.json, and none carry an @ref annotation.

One judgement call worth your attention, which is not a mechanical question and so is yours rather than neutral's:

Those ten files are Phase 0 skeleton placeholders, and each says so in a comment naming what lands there in Phase 2 (config-section registration and validation; the plugin loader, activation lifecycle, and PluginActivationContext materialization). They hold no code, so deleting them is behaviorally inert and mechanically safe. But they encode design intent: a reader who opens src/core/runtime/ currently learns that a plugin loader is planned and where it goes. Removing them removes that signal from the tree, leaving it only in the LLP docs.

If that scaffolding is deliberate, this part of the PR should be dropped and the trims narrowed to the unused imports, locals, and unreferenced exports. If the phased plan has moved on and the placeholders are stale, the deletion is clean.

Generated by neutral's code-cleanup initiative (LLP 0036). Proposed, not asserted.

@philcunliffe

Copy link
Copy Markdown
Contributor Author

Review round 1 - f14a783

Verdict: clean. No blockers, no findings. Every removal is genuinely unreachable.

This was reviewed adversarially: the reviewer's brief was to prove each removed thing is still reachable, not to confirm it is dead. A green suite and a clean typecheck do not prove dead code in a repo with a plugin kernel, config-driven sinks and sources, and string-keyed dispatch, so the burden was on refutation. No reachability path was found for any of the 26 changes.

The decisive check: published package surface

npm run build:types (tsc -p tsconfig.build.json, rootDir: src to outDir: types) was run on both origin/master and this head, exit 0 on each, and the emitted trees diffed:

master: 344 emitted files    head: 334 emitted files
- types/core/registry/{config,queries,skills}.d.ts(.map)
- types/core/runtime/{permissions,plugin_module}.d.ts(.map)

Content diff across the two trees, filtering .map line-number noise, is exactly two hunks: DEFAULT_FLUSH_ROW_CHUNK_SIZE leaving types/core/cache/spool.d.ts and getActiveProvider leaving types/core/observability/tracer.d.ts. Every other emitted .d.ts is byte-identical, which independently confirms that none of the 13 removed imports was still carrying a JSDoc type (the failure mode that typechecks fine but breaks the published declarations).

One detail worth recording, because it settles the Phase 0 question on its own terms: on master each of the five emitted placeholder declarations contains literally export {}. tsc emits declarations from the .js files and does not re-emit hand-written .d.ts inputs, so the src/core/registry/*.d.ts re-exports were never present in the published types/ tree. The shipped files were empty modules. Deleting them is not a breaking change to the package surface.

Reachability, per category

The ten deleted files. Zero references at either revision: no JSDoc @import, no sibling relative import, no doc, no SKILL.md, no .github/, no .claude/skills/. There is only one package.json in the tree (the plugin workspaces have none), its exports has 8 explicit subpaths with no wildcard and no typesVersions, so ./core/registry/* and deep hypaware/src/... paths are blocked to downstream consumers regardless. The two string-built import() sites in the repo (config/discover_section_validators.js:56, which resolves plugin manifest entrypoints, and commands/sink.js:98, a hardcoded literal indirected to dodge TS6059) cannot reach either directory.

The 13 removed imports and two locals. Each binding was grepped with word boundaries in its own file. Four produced hits, all verified false positives on reading: path: as an object property key (commands/status.js:130), a surviving JSDoc @import { Dirent } distinct from the removed value import (daemon/status.js:44), the word "process" in prose comments (remote/credentials.js:473,718), and the string '@hypaware/local-fs' (sink-materialize.test.js). The source exports behind the removed imports (defaultSessionContextFile, defaultBundledWorkspaceDir, datasetsRoot, BATCH_BYTE_LIMIT) all still have live consumers elsewhere and were not orphaned.

The two removed exports, the highest-risk items since an export can have consumers outside this repo. getActiveProvider on a tracer is exactly the shape of a plugin-facing API, so it got the hardest search: zero hits tree-wide at HEAD across src, bin, scripts, test, all plugin workspaces including the tsconfig-excluded */skills directories, llp/, docs/, .claude/, and .github/; on master the only hit is its own definition at tracer.js:74. Same for DEFAULT_FLUSH_ROW_CHUNK_SIZE (sole hit spool.js:19, and it already carried @deprecated Superseded by streaming reader batch limits). Neither is in a barrel: observability/index.js re-exports only getTracer, so the export * from './observability/index.js' in src/core/index.d.ts never carried getActiveProvider. spool.js has no exports subpath at all.

Post-branch drift. origin/master moved to ae63a02 ("Publish v1.19.0") after the branch point. That commit is a one-line version bump and references nothing removed here.

Verification run

Command Result
npm run typecheck exit 0
npm test (head) 2666 tests, 2657 pass, 8 fail, 1 skipped
npm test (baseline origin/master) 2666 tests, 2657 pass, 8 fail - byte-identical failure list
npm run smoke -- local_parquet_export ok (touched by the HERE/fileURLToPath removal)
npm run smoke -- otel_loopback_capture ok (touched by the Attr removal)
npm run build:types on both revisions exit 0 both; diff as above

All 8 failures are the known pre-existing ones in test/core/leave-command.test.js (tests 778-786), identical before and after, and it remains the only failing file. CI on this PR is green on fresh dependencies for Node 22 and 24, which also settles the authoring pass's caveat about having run against symlinked node_modules.

Still a judgement call for the human

The mechanical case is airtight, but see the note above on this PR: five of the deletions are Phase 0 skeleton placeholders whose comments name what lands there in Phase 2. Removing them is behaviorally inert and, as shown, invisible to the published surface, but it does remove design intent from the tree. Whether that scaffolding is deliberate or stale is not a question neutral can answer from git, and it is the one thing worth a human's attention here.

Held for a maintainer. neutral does not merge.

@philcunliffe
philcunliffe marked this pull request as ready for review July 27, 2026 22:10
@philcunliffe philcunliffe added the neutral:approved neutral reviewed this and holds it for a maintainer merge (own or adopted PR; LLP 0025/0030) label Jul 27, 2026
@philcunliffe
philcunliffe merged commit 12eee7c into master Jul 27, 2026
8 checks passed
@philcunliffe
philcunliffe deleted the autophagy/cleanup-2026-07-27 branch July 27, 2026 23:45
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