11 KiB
Refactoring Investigation Report
Overview
This report evaluates the SubMiner refactoring effort on the refactor branch against the plan defined in plan.md and the safety checklist in docs/refactor-main-checklist.md. The refactoring aimed to eliminate unnecessary abstraction layers, consolidate related services, fix known bugs, and add test coverage.
Result: 65 commits, 104 files changed, main.ts reduced from ~5,800 to 1,398 lines, all 67 tests passing, build succeeds.
Phase 1: Delete Thin Wrappers — COMPLETE
All 9 target wrapper services and 7 associated test files have been deleted and their logic inlined into callers (mostly main.ts or the services they fed).
| Target File | Status |
|---|---|
config-warning-runtime-service.ts + test |
Deleted, inlined |
overlay-modal-restore-service.ts + test |
Deleted, inlined |
runtime-options-manager-runtime-service.ts + test |
Deleted, inlined |
app-logging-runtime-service.ts + test |
Deleted, inlined |
overlay-send-service.ts (no test) |
Deleted, inlined |
startup-resource-runtime-service.ts + test |
Deleted, inlined |
config-generation-runtime-service.ts + test |
Deleted, inlined |
app-shutdown-runtime-service.ts + test |
Deleted, inlined |
shortcut-ui-deps-runtime-service.ts + test |
Deleted, inlined |
Files removed: 16 (9 services + 7 tests) No issues found.
Phase 2: Consolidate DI Adapter Services — COMPLETE
All 4 dependency-injection adapter services have been merged into the services they fed, and their test files removed.
| Adapter | Merged Into | Status |
|---|---|---|
cli-command-deps-runtime-service.ts + test |
cli-command-service.ts |
Done |
ipc-deps-runtime-service.ts + test |
ipc-service.ts |
Done |
tokenizer-deps-runtime-service.ts + test |
tokenizer-service.ts |
Done |
app-lifecycle-deps-runtime-service.ts + test |
app-lifecycle-service.ts |
Done |
Files removed: 8 (4 services + 4 tests) No issues found.
Phase 3: Consolidate Related Services — COMPLETE
All planned service merges have been executed.
| Consolidation | Source Files | Result File | Status |
|---|---|---|---|
| Overlay visibility | overlay-visibility-runtime-service.ts |
overlay-visibility-service.ts |
Done |
| Overlay broadcast | overlay-broadcast-runtime-service.ts + test |
overlay-manager-service.ts |
Done |
| Overlay shortcuts | overlay-shortcut-lifecycle-service.ts, overlay-shortcut-fallback-runner.ts |
overlay-shortcut-service.ts + overlay-shortcut-handler.ts |
Done |
| Numeric shortcuts | numeric-shortcut-runtime-service.ts + test, numeric-shortcut-session-service.ts |
numeric-shortcut-service.ts |
Done |
| Startup/bootstrap | startup-bootstrap-runtime-service.ts + test, app-ready-runtime-service.ts + test |
startup-service.ts |
Done |
Files removed: ~10 No issues found.
Phase 4: Fix Bugs and Code Quality — COMPLETE
4.1 Debug console.log statements
Status: RESOLVED — No debug console.log or console.warn calls remain in overlay-visibility-service.ts.
4.2 as never type cast
Status: RESOLVED — No as never cast remains in tokenizer-service.ts. The type mismatch was fixed properly.
4.3 fieldGroupingResolver race condition
Status: RESOLVED — Fixed in main.ts (lines 305–332) with a sequence counter mechanism. Each new resolver increments fieldGroupingResolverSequence, and wrapped resolvers check if their sequence matches the current value before executing. Stale resolutions are correctly ignored.
4.4 Async callback safety
Status: RESOLVED
- CLI commands (
cli-command-service.ts): Async commands userunAsyncWithOsdhelper (lines 177–187) which catches errors, logs them, and displays via MPV OSD. - IPC handlers (
ipc-service.ts): Async handlers useipcMain.handle(not.on), which properly awaits and propagates promise results. Synchronous handlers correctly useipcMain.on.
4.5 -runtime-service naming convention
Status: RESOLVED — No files with -runtime-service in the name exist under src/core/services/. All have been renamed to *-service.ts.
Phase 5: Add Tests for Critical Untested Services — COMPLETE
Tests added per plan:
| Service | Test File | Tests |
|---|---|---|
mpv-service.ts (761 lines) |
mpv-service.test.ts |
Socket protocol, property changes, reconnection |
subsync-service.ts (427 lines) |
subsync-service.test.ts |
Config resolution, command construction, error handling |
tokenizer-service.ts (305 lines) |
tokenizer-service.test.ts |
Parser init, token extraction, edge cases |
cli-command-service.ts (204 lines) |
cli-command-service.test.ts (290 lines) |
Expanded: all dispatch paths, error propagation |
Total: 67 tests passing across all test suites.
Phase 6: Directory Restructure — NOT STARTED (Optional)
Services remain in the flat src/core/services/ directory. This phase was explicitly marked optional and low-priority. The current flat structure with ~25 files is manageable.
Checklist Compliance (docs/refactor-main-checklist.md)
Invariants
| Invariant | Status |
|---|---|
| CLI flags and aliases working | Verified via tests |
| IPC channel names backward-compatible | No channel names changed |
| Overlay toggle behavior preserved | Logic moved verbatim |
| MPV integration behavior preserved | Logic moved verbatim, tested |
| Texthooker mode preserved | Not altered |
| Mining/runtime options paths preserved | Logic moved verbatim |
Automated Checks
| Check | Status |
|---|---|
pnpm run build |
Passes |
pnpm run test:core |
67/67 passing |
Manual Smoke Checks
Status: NOT YET PERFORMED — Visual overlay rendering, card mining flow, and field-grouping interaction require a real desktop session with MPV. Automated tests validate logic correctness but cannot catch rendering regressions.
Loose Ends and Concerns
1. Unused Architectural Scaffolding (~500 lines, dead code)
The following files exist in the repository but are not imported or used anywhere:
Core abstractions:
| File | Lines | Purpose |
|---|---|---|
src/core/action-bus.ts |
22 | Generic action dispatcher (register/dispatch) |
src/core/actions.ts |
17 | Union type AppAction with 16 action variants |
src/core/app-context.ts |
46 | Module context interfaces |
src/core/module-registry.ts |
37 | Module lifecycle manager (init/start/stop) |
src/core/module.ts |
7 | SubminerModule<TContext> interface |
Module implementations:
| File | Lines | Purpose |
|---|---|---|
src/modules/runtime-options/module.ts |
62 | Runtime options module |
src/modules/subsync/module.ts |
79 | Subsync module |
src/modules/jimaku/module.ts |
73 | Jimaku module |
IPC abstraction layer:
| File | Lines | Purpose |
|---|---|---|
src/ipc/contract.ts |
62 | IPC channel name constants |
src/ipc/main-api.ts |
20 | Main process IPC helpers |
src/ipc/renderer-api.ts |
28 | Renderer process IPC helpers |
These represent scaffolding for a module-based architecture that was prototyped but never wired into main.ts. The current codebase uses the service-oriented approach throughout.
Recommendation: Remove if abandoned, or document with clear intent if planned for a future phase.
2. New Consolidated Services Without Test Coverage
Seven service files created or consolidated during Phase 3 lack dedicated tests:
| File | Lines | Risk Level | Reason |
|---|---|---|---|
overlay-shortcut-handler.ts |
216 | Higher | Complex runtime handlers with fallback logic |
mining-service.ts |
179 | Higher | 6 public functions orchestrating mining workflows |
anki-jimaku-service.ts |
173 | Higher | Complex IPC registration with multiple handlers |
startup-service.ts |
~150 | Medium | Bootstrap and app-ready orchestration |
numeric-shortcut-service.ts |
133 | Medium | Session state management |
subsync-runner-service.ts |
86 | Lower | Thin runtime wrapper |
jimaku-service.ts |
81 | Lower | Config accessor functions |
Phase 5 targeted the 4 highest-risk previously existing untested services. The Phase 3 consolidation created new files that inherited logic from multiple sources — those were not explicitly called out in the plan for testing.
3. Null Safety in Consolidated Services
All checked consolidated services handle null/undefined correctly:
mpv-control-service.ts: AcceptsMpvRuntimeClientLike | null, uses null checks and optional chaining before all access.overlay-bridge-service.ts: Returnsfalseearly if window is null or destroyed (line 17: if (!options.mainWindow || options.mainWindow.isDestroyed()) return false).startup-service.ts: Uses dependency injection with all deps provided upfront, async operations awaited in sequence, config access uses optional chaining.
No null safety issues found.
4. Import Consistency
All 68 imports in main.ts from ./core/services resolve to existing exports. No references to deleted files remain. The barrel export in index.ts has 79 entries with no dead exports (one minor case: isGlobalShortcutRegisteredSafe is only used within the service layer itself, not by main.ts).
Risk Assessment
| Area | Risk | Mitigation |
|---|---|---|
| Logic regression from inlining | Low | Code moved verbatim, 67 tests pass |
| Overlay rendering regression | Medium | Requires manual smoke test with MPV |
| Unused scaffolding becoming stale | Low | Remove or document with clear intent |
| Missing test coverage on new files | Medium | Add tests for the 3 higher-risk services |
| Race conditions | Low | fieldGroupingResolver race fixed with sequence counter |
| Async error swallowing | Low | All async paths have error boundaries |
Recommendations
-
Remove unused scaffolding (
src/core/action-bus.ts,src/core/actions.ts,src/core/app-context.ts,src/core/module-registry.ts,src/core/module.ts,src/modules/,src/ipc/) — ~500 lines of dead code that contradicts the refactoring goal of reducing unnecessary abstraction. -
Add tests for higher-risk consolidated services —
overlay-shortcut-handler.ts,mining-service.ts, andanki-jimaku-service.tshave the most complex logic among the untested new files. -
Perform desktop smoke test — Verify overlay rendering, card mining, and field-grouping interaction in a real session with MPV running.
-
Consider removing
isGlobalShortcutRegisteredSafefrom barrel export — It's only used internally by the service layer, not by main.ts.