Skip to content

The Drift Log · Software inventory you can trust

Evicting Stub Entries from Your Internal Component Registry

29 October 2026 · 3 min read · 733 words · established

A vaulted library of glowing green crystal blocks in ordered bays

Static AST parsers count hollow stubs as reusable assets. Test your catalog entries in clean isolation to measure actual runtime capabilities.

Most internal catalogs do not degrade by turning into broken code. They degrade by filling up with tidy, well-documented empty shells.

An engineer registers a utility module for token bucket rate limiting. The markdown documentation is comprehensive, the TypeScript types are cleanly exported, and the repository index lists it as an active asset. But look inside the implementation file: the constructor allocates an options object, logs an initialization string, and exports an empty handler marked // TODO: connect to redis backend. Or worse, it imports an internal client package that was deprecated two major versions ago and throws an unhandled resolution error the moment node loads the module.

Because the file contains valid syntax and exports a recognized interface, static catalog parsers index it without complaint. When the team runs a quarterly report, the component registry reports 340 shared assets available for reuse. In reality, fifty of those entries are non-functional stubs.

A component count is not an inventory. Until a row in your catalog can be executed in complete isolation from the host application, its existence in your documentation is just an unverified claim.

The Mirage of Static Catalog Scrapers

Teams build internal registries to curb redundant work. They configure an indexer to walk their monorepo, parse exported symbols using AST tools, extract JSDoc tags, and push the metadata into a central dashboard.

This static approach catches syntax errors, but it cannot differentiate between operational software and dead code dressed in types. Static extractors fail on three common stub patterns:

  1. Unresolved implicit environment: The module exports a clean function signature, but execution immediately panics because it assumes process.env.APP_STAGE or an active ambient database pool is present at import time.
  2. Hollow implementations: The function fulfills the structural type system by returning a mocked shape or throwing a placeholder error, satisfying the linter while offering zero runtime capability.
  3. Ghost dependencies: The export relies on transitive peer dependencies installed in the monorepo root that will fail to resolve when the module is packaged into an isolated consumer project.

When engineers search the internal library for an existing solution, they pull in one of these hollow entries, spend two hours untangling its missing prerequisites, discover it does not work, and write their own version from scratch. The registry loses credibility, and the organization returns to writing parallel implementations of the same five primitives.

Running in Clean Isolation

Fixing this does not require complex grading rubrics. It requires an execution boundary.

To separate operational assets from stubs, every registered component must pass through an automated code reuse audit that executes its entry point in a clean, throwaway runtime harness.

// harness-runner.ts
import { runInNewContext } from 'node:vm';

export async function testImportBoundary(entryPath: string): Promise<boolean> {
  try {
    // 1. Dynamic import in fresh process/context
    const mod = await import(entryPath);
    
    // 2. Verify export shape actually exists at runtime
    if (typeof mod.createTokenBucket !== 'function') {
      return false;
    }

    // 3. Smoke the constructor without host globals
    const instance = mod.createTokenBucket({ capacity: 10, refillRate: 1 });
    return typeof instance.consume === 'function';
  } catch (err) {
    // Unhandled environmental assumption or broken transitive import
    return false;
  }
}

The difference between reading an interface and executing a dynamic import is where dead code fails. As outlined in running registry entries in isolation, an artifact that cannot execute its own basic instantiation without relying on the host repository's ambient state is not an asset—it is technical debt masquerading as a capability.

When you subject your internal inventory to automated execution tests, the results fall into distinct categories. Code that imports cleanly and runs its contract moves to verified status. Code that fails to load due to missing environment bindings or broken imports gets flagged immediately.

What to Do on Monday

You do not need to rebuild your internal library architecture to strip out hollow entries. Start by auditing the boundary between your documentation and your runtime reality:

  1. Query your current component registry for all exports that have not seen an update or a consumer import in the last six months.
  2. Write a one-page harness script that attempts to dynamically load each exported component inside a vanilla container with no injected environment variables and no global host mocks.
  3. Demote the failures. You do not have to delete the code immediately. Move failing entries into an unpromoted or quarantined state, and strip them from your main catalog search.

An inventory of 40 components that run every time in a clean environment is infinitely more valuable than an internal catalog of 300 entries where half the links lead to stubs. For a deeper look at separating claims from real assets across larger codebases, read our pillar post on why a component count is not an inventory. If you want to see an automated certification harness running against production code, you can inspect the live test run.

Keep reading

Next in the log

The Strategic Master Library · written and reviewed under the house's own epistemic rules: nothing claimed that we cannot show.