# ADR-001: Codebase Hardening — Foundation First

**Date:** 2026-03-17
**Status:** Accepted
**Deciders:** cwarner (project owner), architecture-advisor skill

## Context

The harness-engineering project passes all mechanical checks (build, test, lint, typecheck, format) but has accumulated structural inconsistencies and documentation drift across its 6 packages, 26 skills, and documentation suite. These issues fall into four categories:

1. **Package inconsistency** — Missing scripts (mcp-server has no lint, eslint-plugin has no typecheck), mixed build tools (tsup vs tsc), inconsistent test script defaults, mcp-server missing from tsconfig references.

2. **API surface leaks** — Duplicate `Result<T,E>` in both `@harness-engineering/types` and `packages/core/src/shared/result.ts`. Entropy module exports internal helpers (`levenshteinDistance`, `buildReachabilityMap`). Constraints module mixes `Result<T,E>` with nullable returns. MCP server couples directly to CLI package.

3. **Test coverage gaps** — 7 of 23 MCP server tools lack tests. 16 of 52 CLI source files lack tests. Types package has no tests.

4. **Documentation drift** — `docs/reference/cli.md` documents 9+ nonexistent commands and omits 16+ real ones. All config references say `harness.config.yml` when the implementation uses `harness.config.json`. Config schema documentation describes a different structure than the actual Zod schema. `AGENTS.md` says 21 skills when 26 exist.

These issues don't cause runtime failures today, but they impede contributor onboarding, slow adoption, and will compound as the project grows.

## Decision

Adopt a 4-week bottom-up hardening approach (Option A: Foundation First):

**Week 1 — Package Consistency:**

- Add missing scripts to all 6 packages (lint, typecheck, test, clean) so every package responds to the same set of turbo commands
- Standardize test scripts: `vitest run` as default, `vitest` as `test:watch`
- Add mcp-server to root `tsconfig.json` references
- Evaluate and document build tool choices (tsup vs tsc) per package — standardize where beneficial, document rationale where not

**Week 2 — API Surface Cleanup:**

- Remove duplicate `Result<T,E>` from `core/shared/result.ts`; core re-exports from `@harness-engineering/types` only
- Restrict entropy module exports to public API only; internals become non-exported functions
- Convert `resolveFileToLayer()` and `resolveImportPath()` from nullable returns to `Result<T,E>`
- Audit and minimize mcp-server's dependency on cli package; move shared interfaces to core where appropriate

**Week 3 — Test Coverage:**

- Add tests for all 7 untested MCP server tools (agent-facing API — highest bug-hiding risk)
- Add tests for high-priority CLI subcommands: `skill/run`, `skill/list`, `state/show`, `setup-mcp`
- Add remaining CLI subcommand tests: `persona/*`, `linter/*`, utilities
- Add types package export validation test

**Week 4 — Documentation Overhaul:**

- Rewrite `docs/reference/cli.md` from actual commander registrations
- Fix `docs/reference/configuration.md`: yml->json, document actual Zod schema
- Update `AGENTS.md`: skill count 21->26, add gemini-cli platform, verify all paths
- Fix or remove `docs/api/` placeholder and `docs/changes/` empty directory
- Add CI check that verifies documented CLI commands match registered commands

## Alternatives Considered

### Option B: User-Facing Pain First (Outside-In)

Fix documentation first (Week 1), then package consistency (Week 2), then tests + API cleanup (Week 3). This gets accurate docs to users fastest.

**Why not chosen:** Documentation written against an inconsistent codebase risks needing updates after structural changes in later weeks. Fixing the foundation first means docs are written once against the final state.

### Option C: Surgical Strikes (Risk-Based)

Fix only critical items: cli.md rewrite, yml->json config references, missing lint/typecheck scripts, duplicate Result removal, untested MCP tools. Skip everything else. Done in ~1 week.

**Why not chosen:** The inconsistencies are interconnected. Partial fixes leave technical debt that continues to compound. The project is at a maturity stage where a thorough pass pays dividends — this is the right time to invest.

## Consequences

### Positive

- Every package responds to the same turbo commands — CI catches issues uniformly
- Public API surface is intentional and documented — no accidental internal leaks
- MCP tools (the primary agent-facing API) have complete test coverage — bugs caught before they affect AI interactions
- Documentation matches reality — new users and contributors can follow guides without hitting wrong instructions
- Adding a new package has a clear template to follow because all existing packages are consistent

### Negative

- 4 weeks of hardening work delays feature development — mitigation: each week is independently shippable, so feature work can interleave if priorities shift
- API surface changes (removing duplicate Result, tightening entropy exports, changing nullable returns to Result) may require updates in downstream consumers — mitigation: these are internal packages with no external consumers yet; all changes are caught by existing tests
- Documentation stays wrong during Weeks 1-3 — mitigation: add a temporary banner to docs site noting reference docs are being updated

### Neutral

- Build tool evaluation may conclude that the current tsup/tsc split is actually correct for different package needs — the outcome is documentation of the rationale, not necessarily standardization

## Action Items

- [x] Week 1: Normalize package.json scripts across all 6 packages — owner: cwarner — DONE
- [x] Week 1: Add mcp-server to root tsconfig.json references — owner: cwarner — DONE
- [x] Week 1: Fix 5 lint errors in mcp-server uncovered by new lint script — owner: cwarner — DONE
- [x] Week 2: Remove duplicate Result<T,E> from core/shared/result.ts — owner: cwarner — DONE (now re-exports from types)
- [x] Week 2: Restrict entropy module exports to public API — owner: cwarner — DONE (removed 6 internal helpers from barrel)
- [x] Week 2: Audit constraint nullable returns — owner: cwarner — KEPT AS-IS (resolveFileToLayer returns undefined for "no match" which is semantically correct, not an error; resolveImportPath is private and returns null for external packages)
- [x] Week 2: Audit mcp-server -> cli dependency surface — owner: cwarner — KEPT AS-IS (11 symbols across 6 files, all high-level orchestration functions that are inherently CLI concerns; moving to core would bloat core)
- [x] Week 3: Add tests for 7 untested MCP server tools — owner: cwarner — DONE (5 new test files, 27 new tests, 23/23 test files pass, 107 total tests)
- [x] Week 3: Add tests for untested CLI subcommands — owner: cwarner — DONE (8 new test files, 69 new tests, 49/49 test files pass, 276 total tests)
- [x] Week 4: Rewrite docs/reference/cli.md — owner: cwarner — DONE (complete rewrite from actual commander registrations, 16 commands documented)
- [x] Week 4: Fix docs/reference/configuration.md (yml->json, actual schema) — owner: cwarner — DONE (complete rewrite with actual Zod schema, JSON format, realistic examples)
- [x] Week 4: Update AGENTS.md (skill count, paths, platforms) — owner: cwarner — DONE (10 fixes: skill count 21->26, templates 4->5, test paths, line length, gemini-cli platform, docs placeholders)
- [x] Week 4: Fix docs/api/index.md — owner: cwarner — DONE (updated package list to all 6, added note about missing generated docs)
- [ ] Week 4: Add CI check for doc-code consistency — owner: cwarner — DEFERRED (requires separate PR to add to CI workflow)
