# Feature Spec: OOP-First Refactor of `apps/control-plane` (AOP)

> **Purpose of this document**: Define an implementation-ready plan to refactor the control-plane code under `apps/` to align with strong OOP and clean architecture principles (SRP, KISS, OCP, DIP, ISP, encapsulation), while preserving the existing deterministic MCP/runtime behavior and public contracts.

---

## 1. Objectives

### 1.1 Must-Have Outcomes

- Preserve current behavior and contracts:
  - tool names, request/response envelope shape, and error codes
  - schema-governed state/index/plan formats
  - CLI command and flags (`run`, `status`, `resume`, `stop`, `--transport`, `--takeover-stale-run`)
- Eliminate god objects and high coupling:
  - split `AopKernel` into cohesive domain/application services
  - split `SupervisorRuntime` and `cli/aop.ts` orchestration-heavy logic into dedicated collaborators
- Enforce OOP and type safety:
  - remove cross-layer `as any` dependence from production paths
  - remove broad `[key: string]: any` usage from core runtime classes
  - introduce explicit interfaces for storage, process execution, auth, and orchestration boundaries
- Make tool dispatch open for extension:
  - replace hard-coded `switch(toolName)` dispatch with handler registry and per-tool command handlers
- Reduce duplication and hidden policy drift:
  - centralize mutating-tool metadata currently duplicated in CLI and Supervisor
  - remove side effects from registry-loading code paths where not strictly required
- Improve testability:
  - make each service unit-testable via dependency inversion and narrow interfaces
  - keep and expand behavior-level parity tests for MCP and in-process transports

### 1.2 Non-Goals

- No rewrite of product semantics, workflow semantics, or gate policy semantics.
- No change to canonical artifact locations unless explicitly versioned and documented.
- No replacement of file-backed state model with database-backed storage in this phase.
- No provider feature expansion beyond current provider selection contract.

---

## 2. Current Design Weaknesses (Observed in `apps/`)

### 2.1 God Object / SRP Violations

- `apps/control-plane/src/core/kernel.ts` currently combines:
  - auth/authorization checks
  - schema loading and validation
  - tool routing
  - feature lifecycle and state transitions
  - git/worktree orchestration
  - patch policy enforcement
  - lock lease lifecycle
  - gate execution orchestration
  - QA index logic
  - reporting and merge logic
  - run lease and recovery logic
- This violates SRP and creates high blast radius for change.

### 2.2 OCP and KISS Violations

- `AopKernel.dispatchTool(...)` uses a large switch over tool names.
- Adding a tool currently requires editing central dispatch and often touching unrelated logic.
- CLI and Supervisor each re-implement mutating-tool logic (`MUTATING_TOOLS` sets), increasing drift risk.

### 2.3 DIP/ISP Violations

- `SupervisorRuntime` depends on concrete `AopKernel` behavior and accesses internals via `(kernel as any)` for config and repo root.
- Runtime factory and other modules read internal kernel fields directly instead of consuming typed ports.
- Process, filesystem, and policy dependencies are concretely bound inside core services rather than injected through interfaces.

### 2.4 Encapsulation and Type Safety Gaps

- Broad `any` usage in core/supervisor/cli paths weakens invariants and makes regressions easier.
- State and index access patterns pass loosely typed objects across modules.
- Domain errors and infrastructure errors are not uniformly modeled as typed exceptions/results.

### 2.5 Mixed Concerns and Side Effects

- Tool registry loading also regenerates `tools.md`, coupling startup behavior with documentation generation.
- Auth, authorization, validation, idempotency, execution, and logging are interleaved in `ToolRuntime` without clear policy pipeline abstractions.

---

## 3. Refactor Principles (Normative)

1. **SRP**: each class/service must have one primary reason to change.
2. **KISS**: avoid framework-heavy abstractions; use straightforward interfaces and composition.
3. **OCP**: add tools/behaviors by adding new handlers/services, not modifying core dispatch.
4. **DIP**: depend on interfaces (`ports`), not concrete filesystem/process/kernel implementations.
5. **ISP**: expose small role-specific interfaces rather than broad god interfaces.
6. **Encapsulation**: domain invariants live in domain/application services, not spread across callers.
7. **Composition over inheritance**: prefer coordinator + collaborators over class hierarchies.
8. **Determinism-first**: no refactor may weaken existing deterministic lock/collision/schema/lease behavior.

---

## 4. Target Architecture

### 4.1 Layered Boundaries

- **Domain Layer** (`domain/`):
  - Entities/value objects for `FeatureState`, `Plan`, `RunLease`, `SessionAssignment`, `QaIndex`
  - Domain policies and invariants (legal transitions, plan revision rules, collision semantics)
- **Application Layer** (`application/`):
  - Use-case services for feature init, plan submit/update, patch apply, gates run, locks, merge, reports, recovery
  - Tool handlers that orchestrate domain + infra ports
- **Infrastructure Layer** (`infrastructure/`):
  - filesystem repositories, git command adapter, gate command runner, YAML/schema loader, ledger persistence
- **Interface Layer** (`interfaces/`):
  - CLI commands, MCP adapter, runtime composition root

### 4.2 Port Contracts (Core Interfaces)

- `IndexRepository`
- `FeatureStateRepository`
- `PlanRepository`
- `QaIndexRepository`
- `EvidenceRepository`
- `LockRepository`
- `OperationLedgerRepository`
- `CommandRunner`
- `GitClient`
- `GateRunner`
- `PolicyProvider`
- `SchemaValidator`
- `Clock`
- `IdGenerator`
- `ToolAuthorizerPort`
- `TokenVerifierPort`

### 4.3 Application Services (Initial Set)

- `RunLeaseService`
- `FeatureLifecycleService`
- `FeatureStateService`
- `PlanService`
- `PatchService`
- `GateService`
- `LockService`
- `MergeService`
- `QaIndexService`
- `ReportingService`
- `RecoveryService`
- `SessionAssignmentService`

### 4.4 Tool Dispatch Model

- Replace kernel switch dispatch with:
  - `ToolHandler` interface: `execute(args, context): Promise<ToolResponse>`
  - `ToolHandlerRegistry`: map of tool name to handler
  - `ToolRouter`: centralized routing with typed unknown-tool handling
- MCP and in-process runtime both call the same handler layer through a shared application boundary.

---

## 5. Walkthrough Refactor Plan for `apps/` Files

### 5.1 `apps/control-plane/src/core/*`

- `core/kernel.ts`
  - Decompose into domain/application service classes listed in Section 4.3.
  - Keep a thin façade (`AopKernelFacade`) temporarily for backward compatibility during migration.
  - Remove dynamic `[key: string]: any`.
- `core/gates.ts`
  - Split into:
    - `GateExecutionService`
    - `CoverageParserStrategy` (`lcov`, `junit_xml`, `jacoco_xml`, `cobertura_xml`)
    - `CoverageThresholdPolicy`
  - Keep current parser behavior unchanged.
- `core/fs.ts`
  - Split atomic file writer and lock manager:
    - `AtomicFileWriter`
    - `FileLockManager`
    - `PathFsAdapter`
- `core/git.ts`
  - Introduce `GitClient` interface and `NodeGitClient` implementation.
  - Preserve `runCommand` behavior via `CommandRunner` abstraction.
- `core/schemas.ts`
  - Promote `SchemaRegistry` to typed validator service with explicit schema IDs.
  - Remove `any` from AJV access points.
- `core/patch.ts`
  - Convert to `DiffParser` domain utility with typed parse errors.
- `core/qa-index.ts`
  - Move update/version rules into `QaIndexDomainService` and keep repository logic separate.
- `core/path-rules.ts`
  - Split normalization from matching policy:
    - `RepoPathNormalizer`
    - `AreaMatchingPolicy`
- `core/frontmatter.ts`
  - Keep as utility but wrap in `StateMarkdownSerializer`.
- `core/response.ts`
  - Preserve wire envelope; add typed result helpers for internal app layer.
- `core/error-codes.ts`
  - Preserve codes; add typed domain/application error mapping.
- `core/constants.ts`
  - Keep protocol constants; move mutating tool metadata to shared tool metadata module.

### 5.2 `apps/control-plane/src/mcp/*`

- `mcp/tool-runtime.ts`
  - Refactor into explicit policy pipeline:
    1. authorize scope/role
    2. validate input
    3. idempotency precheck
    4. execute handler
    5. validate output/error envelope
    6. idempotency record
    7. emit audit log
  - Keep behavior parity; improve readability and test seam isolation.
- `mcp/tool-registry-loader.ts`
  - Separate responsibilities:
    - `ToolRegistryLoader` (read + validate)
    - `ToolsMarkdownGenerator` (doc generation)
  - Make docs generation explicit (startup hook or dedicated command).
- `mcp/tool-contract-validator.ts`
  - Replace broad `any` with typed AJV wrapper.
- `mcp/token-auth-verifier.ts`
  - Split JWT codec/signature and claim validation into separate components.
- `mcp/tool-authorizer.ts`
  - Keep policy intersection behavior; expose interface for application layer.
- `mcp/operation-ledger.ts`
  - Extract persistence from idempotency policy decisions.
- `mcp/kernel-tool-executor.ts`
  - Replace kernel dependency with application tool router interface.
- `mcp/mcp-server-adapter.ts`
  - Keep as transport adapter only; no domain logic.
- `mcp/runtime-factory.ts`
  - Move construction into composition root with explicit dependency graph and config object.
- `mcp/tool-client.ts`
  - Keep clients; centralize operation-id policy in shared metadata module.
- `mcp/types.ts`
  - Keep contract models; split internal runtime-only types from transport DTOs.

### 5.3 `apps/control-plane/src/supervisor/runtime.ts`

- Split into:
  - `RunCoordinator`
  - `SessionOrchestrator`
  - `PlanningWaveExecutor`
  - `BuildWaveExecutor`
  - `QaWaveExecutor`
  - `PromptBundleLoader`
  - `LeaseHeartbeatService`
- Remove direct access to kernel internals and replace with typed ports:
  - `RuntimeStateReader`
  - `FeatureOrchestrationPort`
  - `AgentPromptProvider`

### 5.4 `apps/control-plane/src/cli/aop.ts`

- Split command concerns:
  - `CliArgumentParser`
  - `RunCommandHandler`
  - `StatusCommandHandler`
  - `ResumeCommandHandler`
  - `StopCommandHandler`
  - `SpecInputResolver`
  - `SpecIngestionService`
- Keep CLI contract unchanged; remove operational logic from entrypoint.
- Replace inline bootstrapping with composition root in `interfaces/cli/bootstrap.ts`.

### 5.5 `apps/control-plane/src/providers/providers.ts`

- Introduce provider interfaces:
  - `WorkerProvider`
  - `ProviderSelectionResolver`
- Keep `NullWorkerProvider` as test/default adapter, but isolate provider-agnostic behavior in shared abstractions.

### 5.6 `apps/control-plane/src/index.ts`

- Export only stable public API surface from composition root and major interfaces.

### 5.7 `apps/control-plane/test/*`

- Keep behavior tests, but re-balance:
  - domain service unit tests (fast, pure)
  - infrastructure adapter tests (filesystem/git behavior)
  - transport parity tests (in-process vs MCP)
  - CLI integration tests
- Reduce brittle casts and internal state poking where possible.
- Add characterization tests before decomposition for high-risk paths:
  - plan submit/update rules
  - lock acquisition/release and stale reclaim behavior
  - merge gating preconditions
  - lease takeover behavior
  - idempotent mutation replay/mismatch

---

## 6. Proposed Target File Layout

```text
apps/control-plane/src/
  application/
    services/
    tools/
    ports/
  domain/
    models/
    policies/
    errors/
  infrastructure/
    fs/
    git/
    schema/
    ledger/
    gates/
  interfaces/
    cli/
    mcp/
    supervisor/
  composition/
    runtime-factory.ts
  index.ts
```

---

## 7. Migration Milestones

### OOP-M1: Safety Net and Characterization

- Freeze behavior via characterization tests around current kernel and supervisor critical flows.
- Add per-tool parity assertions for in-process and MCP clients.

### OOP-M2: Shared Contracts and Metadata

- Introduce typed command/context/result contracts.
- Centralize tool metadata including mutating-tool flags.
- Remove duplicated `MUTATING_TOOLS` declarations.

### OOP-M3: Kernel Decomposition Phase 1

- Extract pure domain policies:
  - status transitions
  - plan revision rules
  - collision and lock requirement rules
- Keep compatibility façade delegating to extracted services.

### OOP-M4: Kernel Decomposition Phase 2

- Extract repositories and infra adapters for state/index/plan/qa/evidence/git.
- Migrate façade methods to use application services only.

### OOP-M5: Tool Routing Refactor

- Replace `switch` dispatch with handler registry and router.
- Add per-handler unit tests.

### OOP-M6: Supervisor and CLI Separation

- Split supervisor waves and session orchestration components.
- Split CLI command handlers and input ingestion services.
- Remove `(kernel as any)` access in production code.

### OOP-M7: MCP Runtime Pipeline Cleanup

- Convert ToolRuntime flow into explicit pipeline components.
- Isolate registry loading and documentation generation concerns.

### OOP-M8: Hardening and Finalization

- Remove deprecated façade code paths.
- Enforce type/lint architecture rules.
- Run full test suite and document architecture in README and spec progress.

---

## 8. Acceptance Criteria

1. All existing externally visible contracts remain compatible.
2. `AopKernel` is reduced to a thin façade or replaced by composed services with no monolithic business logic block.
3. Tool dispatch is registry/handler-driven (no large central switch statement).
4. No duplicated mutating-tool policy declarations across CLI and Supervisor.
5. Supervisor and CLI do not use `(kernel as any)` to read internals.
6. Core production paths compile without broad `any` escape hatches except where unavoidable for third-party boundaries.
7. MCP and in-process transport parity tests remain green for critical tool paths.
8. Existing deterministic guarantees (locks, schema validation, optimistic concurrency, idempotency, transitions) are preserved.

---

## 9. Risks and Mitigations

- Risk: behavior regressions during decomposition.
  - Mitigation: characterization tests before migration and phased extraction with compatibility façade.
- Risk: over-abstraction and complexity increase.
  - Mitigation: enforce KISS and prefer minimal interfaces with concrete implementations.
- Risk: refactor stalls due to broad scope.
  - Mitigation: milestone-based delivery with independently mergeable phases.
- Risk: test flakiness with git/worktree behavior.
  - Mitigation: isolate process and filesystem adapters, then test them directly.

---

## 10. Execution Backlog (Initial)

- `OOP-T-001`: Add characterization tests for kernel high-risk flows.
- `OOP-T-002`: Create shared tool metadata module and remove duplicate mutating sets.
- `OOP-T-003`: Introduce application-layer port interfaces and context types.
- `OOP-T-004`: Extract state/index repositories from kernel.
- `OOP-T-005`: Extract run lease + lock services from kernel.
- `OOP-T-006`: Extract plan/patch/gate/merge services from kernel.
- `OOP-T-007`: Replace kernel dispatch switch with handler registry.
- `OOP-T-008`: Refactor SupervisorRuntime into coordinator + wave executors.
- `OOP-T-009`: Refactor CLI into command handlers + composition root.
- `OOP-T-010`: Refactor ToolRuntime into explicit pipeline components.
- `OOP-T-011`: Remove production `(as any)` internal field access patterns.
- `OOP-T-012`: Architecture verification pass (typecheck + test + contract parity).

---

## 11. Rollout Notes

- This refactor should be executed after or in parallel-safe slices with existing roadmap milestones, with each OOP milestone producing a shippable state.
- Keep schema contracts and tool registry contracts authoritative during the refactor.
- Any intentional contract changes must be versioned and documented in `spec-files/progress.md` and corresponding specs before implementation.
