SDD + TDD + cross-runtime QA
Three composable verification discipline layers — spec-driven acceptance criteria, test-first diff gate, and cross-runtime fan-out comparison — all flowing through the same verification.yaml + events.ndjson pipeline.
Ultimate Harness ships three composable verification disciplines. Each one is opt-in, each one is independently testable, each one writes to the same verification.yaml + events.ndjson pipeline so live observers (the TUI, future replay tools, audit consumers) never need a special code path.
Last updated: 2026-05-18. Shipped via UH-54 (SDD), UH-55 (TDD), UH-56 (cross-runtime QA).
1. Spec-Driven Development (UH-54)
Promise: every claim a mission makes about what "done" looks like is independently verifiable, machine-checked, and traced in the audit log.
Schema (mission.yaml):
acceptance_criteria:
- id: ac-tui-dashboard
description: "uh tui shows a Mission Control dashboard"
check_command: "bun test tests/tui-dashboard.test.ts"
severity: block
- id: ac-events-latency
description: "Live events render within 50 ms"
check_command: "bun run bench:tui-events"
severity: warn| Field | Required | Notes |
|---|---|---|
id | yes | stable slug; unique within the mission; appears in audit trail |
description | yes | human-readable |
check_command | no | shell command run from the sandbox/root; exit 0 = pass |
severity | no (default block) | block fails the mission on failure; warn records and continues |
What uh verify does:
- Runs every
required_checkfirst (legacy contract). - Runs every AC's
check_commandin declared order. - Captures
{status, exit_code, duration_ms, stdout_snippet, stderr_snippet}per AC intoverification.yaml#acceptance_criteria[]. - Emits
acceptance.checkedrows onevents.ndjsonso the TUI's live tail surfaces per-AC progress. - Escalates
verification.status:- any
blockAC failed →failed - any
blockAC unverified (nocheck_command) →blocked+ finding - otherwise the legacy
required_checkssemantics apply
- any
Backwards compatibility: missions that omit acceptance_criteria continue to verify against completion_criteria / required_checks. Plain completion_criteria strings auto-promote to severity: warn ACs so legacy missions still surface their intent in the audit trail.
2. Test-Driven Development (UH-55)
Promise: missions that opt in cannot ship a diff that touches source files without also touching tests.
Schema (mission.yaml):
tdd:
enforce_tests_first: true
test_paths:
- "tests/**"
- "**/*.test.ts"
- "**/*.spec.ts"
- "**/__tests__/**"
source_paths:
- "src/**"| Field | Default | Notes |
|---|---|---|
enforce_tests_first | true | the only field that actually gates verification today |
test_paths | conventional set | globs evaluated against the captured diff.patch |
source_paths | ["src/**"] | test globs win over source globs (so src/foo.test.ts is a test) |
What uh verify does:
- Reads the captured
diff.patchfrom the mission directory. - Calls
classifyDiff(diff, …)(a pure helper insrc/harness/diff-classifier.ts) that walks unified-diff hunks, extracts every touched path (handles--- /dev/null, renames, C-quoted paths), and buckets each intotests/source/other. - Appends a synthetic
acceptance_criteriaentryac-tdd-tests-precede-code(severityblock) to the same UH-54 pipeline:- source files changed without tests → AC
failed, runfailed - any test change → AC
passed - no
diff.patchcaptured → ACblocked, runblocked+ finding
- source files changed without tests → AC
- The synthetic AC participates in event emission (
acceptance.checkedwithsynthetic: true), status escalation, and CLI summaries identically to a user-declared AC.
Opt-in: missions without a tdd block behave exactly as before.
3. Cross-runtime QA (UH-56)
Promise: the same mission can be run against every active adapter; the harness produces a side-by-side report that highlights agreement and divergence in the captured diffs.
CLI:
uh mission run-all <mission-id> [--runtimes hermes,codex,hermes-proxy,oh-my-pi]
[--root <path>] [--serial]--runtimesdefaults to every adapter under.harness/adapters/withstatus: active.- One sandbox per runtime, named
sbx-<missionId>-<runtime>-<short-ts>, created serially to avoid racing the unlockedsandboxes/index.yamlread-modify-write. - Adapter runs dispatch in parallel once sandboxes are prepared (or sequentially with
--serial). - Sandboxes are not auto-discarded — the operator inspects each worktree before deciding.
Artifacts written:
.harness/sandboxes/<sandbox>/worktree/.harness/missions/<id>/— each runtime'sruntime-session.yaml+diff.patch+runtime-final.txt..harness/missions/<id>/runtime-comparison.md— the markdown report with:- per-runtime status table (status / exit / duration / diff hash / sandbox)
- diff equivalence groups (which runtimes produced identical diffs)
- per-runtime touched-paths list
- per-runtime sentinel block
.harness/missions/<id>/events.ndjson— appendedruntime.comparedrows and one finalruntime.comparison.summaryrow.
Exit codes:
| Outcome | Code |
|---|---|
| All runtimes succeeded AND diffs agree | 0 |
| Diffs diverged | 1 |
| Any runtime failed / blocked / errored | 1 |
Agreement semantics: "agreement" requires ≥ 2 successful runtimes that share a diffHash. A single successful runtime is not enough.
4. How the three stack
Run a TDD mission against three adapters and you get:
$ uh mission run-all my-bugfix
[DIVERGENT] my-bugfix
runtimes: 3 succeeded, 0 not
report: …/.harness/missions/my-bugfix/runtime-comparison.md
divergent: oh-my-piThen verify against the canonical mission:
$ uh verify my-bugfix
[FAIL] my-bugfix
checks: 0 passed, 0 failed, 0 blocked
acceptance: 1 passed, 1 block-failed, 0 warn-failed, 0 blocked (total 2)
see acceptance_criteria[] in …/verification.yaml for per-AC stdout/stderr snippetsThe block-failed AC is ac-tdd-tests-precede-code because (say) oh-my-pi shipped a source-only diff. Add a runtime-comparison AC to the mission's acceptance_criteria if you want divergence itself to gate promotion:
acceptance_criteria:
- id: ac-cross-runtime-agreement
description: "All active adapters agree on the diff"
check_command: "test \"$(yq '.divergent_runtimes | length' .harness/missions/${MISSION_ID}/runtime-comparison.json)\" = 0"
severity: warn5. References
src/schema/mission.ts—AcceptanceCriterionSchema,TddOptionsSchema.src/schema/artifacts.ts—AcceptanceCriterionResultSchema,VerificationResultSchema.src/harness/verify.ts—verifyMission,runCommand, AC loop, TDD synthetic AC.src/harness/diff-classifier.ts—globToRegExp,extractDiffPaths,classifyDiff.src/harness/run-all.ts—runMissionAcrossRuntimes,compareRuntimeOutcomes,renderRuntimeComparisonMarkdown,persistRuntimeComparison.tests/verify.test.ts— covers both UH-54 (8 cases) and UH-55 (7 cases).tests/diff-classifier.test.ts— 17 cases.tests/run-all.test.ts— 15 cases.
Verification and Promotion Lifecycle
Agent output is not complete when the runtime says it is done. It is complete only when required checks pass, review gates are satisfied, and approved artifacts are promoted.
UH-41 — Interactive TUI architecture
Epic-level architecture document for the `uh tui` Mission Control interface. Captures the load-bearing decisions from the [UH-46 grill](https://linear.app/agenticengineering-agency/issue/UH-46) so downstream slices (UH-47 mission browser, UH-44 mission r