11 KiB
APOPHIS Codebase Bloat Assessment
Date: 2026-04-29 Scope: src/ directory (214 files, ~51,315 lines) Goal: Identify consolidation opportunities without functional changes
Executive Summary
The codebase has grown organically through rapid feature delivery. While functional, it exhibits several bloat patterns:
- 17% of source files are under 30 lines (36 files) - excessive fragmentation
- Test utilities duplicated across 9+ files - same helpers redefined
- 7 builder files with identical patterns - could be unified
- ~2,500 lines of dead/unused code - zero imports
- Massive types.ts monolith (636 lines) - imported by 64 files, high coupling
- CLI commands average 450+ lines each - complex control flow
Estimated consolidation potential: ~8,000-12,000 lines (15-23% reduction)
1. Module Fragmentation (36 files under 30 lines)
Critical Issues
| File | Lines | Issue | Suggestion |
|---|---|---|---|
src/plugin/cleanup-builder.ts |
12 | Single wrapper function | Merge into cleanup-manager.ts |
src/plugin/scenario-builder.ts |
16 | Thin wrapper | Merge into plugin/index.ts or unified builder |
src/plugin/swagger.ts |
15 | Single export | Merge into spec-builder.ts |
src/infrastructure/security.ts |
25 | Constants only | Merge into http-executor.ts or types.ts |
src/infrastructure/logger.ts |
22 | Logger setup | Merge into plugin/index.ts |
src/infrastructure/seeded-rng.ts |
30 | Small utility | Move to test/ or merge into utilities |
src/test/precondition-checker.ts |
12 | Always returns true | Delete - dead abstraction |
src/cli/core/exit-codes.ts |
10 | Constants only | Merge into cli/core/types.ts |
src/cli/renderers/index.ts |
10 | Barrel file, zero consumers | Delete |
Barrel Files (7 files)
All are under 10 lines and just re-export. Modern bundlers handle this; they're unnecessary:
src/extensions/serializers/index.tssrc/extensions/sse/index.tssrc/extensions/websocket/index.tssrc/cli/index.ts(10 lines, just exports main)src/cli/renderers/index.ts(zero consumers)
Impact: Remove ~15 files, save ~300 lines
2. Type Duplication
The types.ts Monolith Problem
src/types.ts (636 lines, 43 exports) is imported by 64 files - a high-fan-in coupling point.
Issues:
RouteContractdefined here AND referenced insrc/cli/core/types.tsEnvironmentPolicy,ProfileDefinition,PresetDefinitiondefined in BOTHsrc/types.tsANDsrc/cli/core/config-loader.tsHttpMethodunion duplicated conceptually across parser, evaluator, and types
Suggested split:
src/types/
core.ts # Plugin types (RouteContract, EvalContext, etc.)
cli.ts # CLI types (Config, ProfileDefinition, etc.)
formula.ts # Formula types (OperationHeader, Comparator, etc.)
extension.ts # Extension types
Impact: Smaller import surfaces, clearer ownership boundaries, and potentially narrower recompilation impact
Formula Type Sprawl
src/formula/types.ts(131 lines):OperationHeader,Comparator,FormulaNodesrc/domain/formula.ts(45 lines): Mirrors some formula typessrc/types.ts(lines 115-140): Also defines formula-related types
Impact: Merge into single src/formula/types.ts, remove from src/types.ts
3. Utility Sprawl in Tests (30+ helper files)
Identical Functions Defined Multiple Times
APOPHIS_INTERNALS array and captureTestStack():
src/test/runner-utils.ts(lines 15-25)src/test/stateful-result-utils.ts(lines 12-22)- Exact same code in both files
deduplicateFailures:
src/test/runner-utils.ts(lines 45-66)src/test/result-deduplicator.ts(lines 20-50)- Different signatures but same purpose
Route filtering:
src/test/petit-suite-utils.ts(67L)src/test/route-filter.ts(73L)- Both filter routes by scope/patterns with overlapping logic
Formatter Proliferation
4 separate formatting utilities that could be unified:
src/test/error-renderer.ts(93L) - renders errorssrc/test/counterexample-formatter.ts(108L) - formats counterexamplessrc/test/tap-formatter.ts(110L) - TAP formatsrc/test/result-formatter.ts(74L) - result formatting
Suggestion: Single src/test/formatters.ts with format strategies
Impact: Merge 8 files into 3, save ~400 lines
4. Builder Pattern Proliferation (7 files)
All builders in src/plugin/ follow identical pattern:
export const buildX = (deps) => async (opts) => { ... }
| Builder | Lines | Complexity |
|---|---|---|
check-builder.ts |
45 | Medium |
cleanup-builder.ts |
12 | Trivial |
contract-builder.ts |
89 | High |
scenario-builder.ts |
16 | Trivial |
spec-builder.ts |
25 | Low |
stateful-builder.ts |
32 | Low |
swagger.ts |
15 | Trivial |
Suggestion: Unified builder system
// src/plugin/builders.ts
export const builders = {
check: (deps) => async (opts) => { ... },
cleanup: (cm) => async () => cm.cleanup(), // 1-liner
contract: (deps) => async (opts) => { ... },
// etc.
}
Impact: 7 files → 1 file, save ~150 lines of boilerplate
5. Test File Bloat (88 files, 26,938 lines)
Over-Testing
src/test/cli/config-validation.test.ts is 4,194 lines with 279 test cases.
- Tests every permutation of invalid config
- Could use parameterized tests or property-based testing
- Potential reduction: 4,194 → ~800 lines (80%)
Duplicate Test Helpers
17 CLI test files define their own:
makeCtx()- defined in 9 filescreateTestContext()- defined in 7 filescreateTempDir()- defined in 9 filescleanup()- defined in 9 files
Suggestion: src/test/cli/helpers.ts with shared test utilities
Overlapping Test Concerns
acceptance.test.ts(328L) andregression.test.ts(259L) both test "run all commands"verify.test.tsandverify-ux.test.tstest similar verify behaviordoctor.test.tsanddoctor-consistency.test.tsoverlap
Impact: Merge/parameterize tests, save ~2,000 lines
6. Redundant Abstractions
Type-Only Files
| File | Lines | Content | Suggestion |
|---|---|---|---|
src/infrastructure/cleanup.ts |
18 | Types only | Merge into cleanup-manager.ts |
src/infrastructure/cache.ts |
23 | Types only | Merge into incremental/cache.ts |
src/infrastructure/http-types.ts |
32 | 3 interfaces | Merge into types.ts or http-executor.ts |
src/infrastructure/security.ts |
25 | Constants | Merge into http-executor.ts |
Dead Abstractions
src/test/precondition-checker.ts(12L):checkPreconditions()always returnstruesrc/test/plugin-contract-composer.ts(24L):composeEnsures()never importedsrc/cli/renderers/index.ts(10L): Barrel file, zero consumers
Impact: Remove 5 files, save ~100 lines
7. Dead Code (Zero Imports)
| File | Lines | Reason |
|---|---|---|
src/protocol-packs/index.ts |
184 | New feature, not integrated yet |
src/quality/mutation.ts |
298 | Mutation testing, not wired |
src/test/result-formatter.ts |
74 | Replaced by other formatters |
src/test/hypermedia-validator.ts |
307 | Only used by its own test |
src/test/cascade-validator.ts |
185 | Only used by its own test |
src/test/error-renderer.ts |
93 | Only used by counterexample.test.ts |
Total dead code: ~1,141 lines
Note: protocol-packs/index.ts should be kept (new feature), but mutation.ts and test-only utilities should be evaluated.
8. Control Flow Complexity
Most Complex Functions (by control-flow statements)
| File | Lines | Control-Flow | Issue |
|---|---|---|---|
src/cli/commands/qualify/index.ts |
650 | 130 | Giant command handler |
src/cli/commands/verify/index.ts |
505 | 122 | Too many branches |
src/cli/commands/replay/index.ts |
513 | 116 | Complex fallback logic |
src/quality/chaos-v3.ts |
504 | 82 | Large switch statements and high branch count |
src/domain/contract-validation.ts |
301 | 53 | Deep nesting |
src/test/scenario-runner.ts |
283 | 47 | Cookie/form/capture logic |
Specific Issues
src/test/failure-analyzer.ts (143L, 40 control-flow):
- 15+ sequential if-else branches for different failure patterns
- Could use a pattern table/dictionary:
const analyzers = {
'timeout': analyzeTimeout,
'crash': analyzeCrash,
// etc.
}
src/cli/commands/qualify/index.ts (650L):
- Handles scenario, stateful, AND chaos execution
- Could split into sub-handlers:
// qualify/index.ts - orchestrator only
// qualify/scenario-handler.ts
// qualify/stateful-handler.ts
// qualify/chaos-handler.ts
src/quality/chaos-v3.ts (504L):
- Large switch statements for event types
- Could use strategy pattern or event registry
Consolidation Roadmap
Phase 1: Quick Wins (Low Risk, High Impact)
- Delete dead files:
precondition-checker.ts,cli/renderers/index.ts - Merge tiny builders:
cleanup-builder.ts,scenario-builder.ts→plugin/builders.ts - Merge type-only files:
cleanup.ts,cache.ts,http-types.tsinto their implementations - Remove barrel files: 7 index.ts files
Estimated savings: ~1,500 lines, 15 files removed
Phase 2: Test Consolidation (Medium Risk)
- Create
src/test/cli/helpers.ts: Shared test utilities - Parameterize config-validation tests: Reduce 4,194 lines
- Merge overlapping test files: acceptance + regression, verify + verify-ux
- Consolidate formatters: Single formatter module
Estimated savings: ~3,000 lines, 20 files removed
Phase 3: Structural Refactoring (Higher Risk)
- Split
types.tsmonolith: Into domain-specific type modules - Unified builder system: Single builders.ts with all build functions
- Split CLI commands: Sub-handlers for qualify, verify
- Pattern-table refactor: failure-analyzer, chaos-v3
Estimated savings: ~4,000 lines, improved maintainability
Phase 4: Architecture Cleanup
- Evaluate protocol-packs integration: Wire into config system or remove
- Evaluate mutation.ts: Wire into test runner or remove
- Review extension system: 15 extension files, some may be redundant
Metrics Summary
| Category | Current | Target | Reduction |
|---|---|---|---|
| Source files | 214 | ~170 | 20% |
| Source lines | 51,315 | ~42,000 | 18% |
| Test files | 88 | ~65 | 26% |
| Test lines | 26,938 | ~20,000 | 26% |
| Files under 30L | 36 | 5 | 86% |
| Dead code files | 6 | 0 | 100% |
Total potential reduction: ~16,000 lines (21% of codebase)
Recommendations Priority
- Immediate (this week): Delete dead files, merge tiny builders, remove barrel files
- Short-term (next 2 weeks): Test consolidation, shared helpers
- Medium-term (next month): types.ts split, builder unification
- Long-term (next quarter): CLI command refactoring, pattern tables
Report generated without code changes. All metrics based on static analysis.