# Software Factory Adoption Plan — harness v2 → factory contracts

audience: AI coding agents first.

**Verdict:** Keep harness v2 as execution substrate (worktrees, waves, multi-provider seats, fail taxonomy, landing). Do NOT rebuild it. Retrofit the missing factory layer — validated output contracts, claim gates, acceptance semantics, per-phase observability — ported from SSSF (disler/super-simple-software-factory, MIT; vendored at `modules/harness/reference/sssf/`). Principle: agents propose, code disposes.

**Why:** v2 pains are low run success rate + unusable observability. Survey (2026-08-03, gpt-5.6-sol over live tree) found the causes are contract seams, not the substrate:
- Wrapper replies are free text + one optional JSON line; `parseWrapperReply` takes last JSON object, NO schema validation.
- Review verdicts advisory; malformed review → no structured verdict event, run proceeds.
- Exit 0 accepted when agent merely claims no-op.
- Phase success conflated with run acceptance.
- Prompts/costs/tool calls captured inconsistently per provider; /plans UI can't answer "what did this agent see and produce".
- Spec/impl drift: reliability spec says foreground-only; `runner.js` still carries daemon submission paths.

Engine source: `modules/harness/v2` on origin/main (flat layout — the deployed bundle's source). `modules/harness/src` is DEAD parked WIP ("Park WIP before AI OS migration", branch-only) — never target or integrate it. NOTE: the survey findings above were taken on the dead layout; the live engine already fixes several (reply-shape mining, blocking review, empty-diff). Authoritative re-verified gap list lives in the SPEC files.

## Keep verbatim (our needs SSSF does not cover — never regress these)

Waves + same-wave concurrency, per-task git worktrees, multi-provider seat presets + cost policy, resume from journal, failureClass taxonomy + stop-loss, quarantine/repair, landing via ship.sh, remote runners, protected paths.

## Port from SSSF (semantics, not transliteration — engine is Node; write zod, not pydantic)

| # | SSSF mechanism | Source (vendored) | Lands in |
|---|---|---|---|
| 1 | Typed envelopes: every agent call declares output schema; parse failure re-prompts SAME session, bounded (`JSON_FIX_ATTEMPTS`) | `adw_modules/agents.py` `_parse_with_retries`, `data_types.py` `EnvelopeBase` | wrapper reply path (`parseWrapperReply` callers) |
| 2 | Claim gates: `artifacts_exist`, `files_non_empty`, `diff_matches_claims`, `verdict_consistent`; violations return to same session as corrections | `adw_modules/gates.py` | post-attempt validation in `engine/ship.js` task loop |
| 3 | Success must be earned: phase defaults fail; `run.finish(accepted=)` separates phases-passed from run-accepted; db + exit code + banner decided together | `adw_modules/runner.py` | run completion path + journal |
| 4 | Trace completeness: compiled prompts saved per call; per-attempt usage/cost (`UsageBreakdown`); tool_call events with spans; process pids per run; context occupancy per agent | `adw_modules/tracer.py` schema, `agents.py` | journal schema + wrapper normalization |
| 5 | Contract triad rule: output type + prompt `## Report` JSON example + call-site `output_type=` are ONE contract — change one, change all three | `SKILL.md` hard rule 2 | seat prompt templates + adapter code |
| 6 | Simple linear chains for small work: scout, plan→build→test as thin scripts over engine primitives — small task never pays full engine | `adws/adw_simple_sdlc.py`, `adw_scout.py` | new thin entry points beside `runplan` |
| 7 | Phase descriptions required + anti-echo validated at construction | `data_types.py` `PhaseParams` | plan JSONL validation |

## Phases (execution: attended orchestration per `docs/plans/2026-08-03-factory-execution-plan.md` — NOT unattended runplan, by user order 2026-08-03: zero trusted observability today)

**P0 — Measure baseline.** Aggregate ALL historical runs via the registry `~/.harness/runs/*.json`, journal DBs discovered ONLY through registry pointers (never guessed paths): success %, failureClass distribution, cost per run, loop offenders. Exit: numbers in `docs/plans/factory-baseline-report.md`. No numbers → later phases unmeasurable; this phase is NOT optional.

**P1 — Output contracts (port rows 1, 2, 3, 5).** Zod schema per seat reply (build/review/fix/resolve). Parse failure → bounded same-session correction. Claim gates after every attempt. Review verdict becomes enforced: malformed/missing → attempt fails with its own failureClass, never silent-proceed. Split `accepted` from phases-ok in journal + exit code. Exit: every agent attempt in a run journal has either a valid envelope row or a classified contract failure; zero free-text acceptance paths left.

**P2 — Observability (port row 4).** Journal captures per attempt: compiled prompt (system+user), envelope, gate results with evidence notes, usage/cost, tool calls, pid, context occupancy. /plans run view answers, per phase: who ran, which model, what it was told, what it returned, what gates said, what it cost. Reuse existing components; honor /plans componentization mandate (memory `plans-ui-componentization-mandate`). Exit: pick any historical failed run in UI, identify failing phase + its prompt + its output without opening a terminal.

**P3 — Thin chains (port rows 6, 7).** `scout` and `plan-build-test` linear workflows reusing engine primitives (worktree, wrapper call, gate0, journal). Orchestrator = run-plan skill routes small requests to thin chains, big plans to full engine. Exit: scout run end-to-end on a real repo, observable in /plans.

**P4 — Seam closure.** Kill exit-0-no-op acceptance (no-op claim must carry evidence gate). Resolve foreground/daemon spec drift one way. Enforce dependency wave-ordering at plan validation. Exit: survey seams list empty or each remaining seam has a written justification.

## Rules for implementers

- Port semantics into engine idiom. DO NOT bolt a Python sidecar onto the Node engine.
- Contract triad (row 5) binds every seat you touch: grep the type name, update all call sites + prompt examples in the same change.
- Every phase change lands behind existing tests + gate0. New contracts get unit tests against recorded real wrapper replies (good + malformed).
- Baseline numbers from P0 are the scoreboard: re-run the P0 script after P1 and P4; success rate must move or the change is wrong.
