Verification & Validation Paradigm
Wave uses a three-layer V&V model to ensure pipeline outputs meet quality, structural, and behavioral requirements. Each layer operates at a different level of abstraction and catches different classes of problems.
Layer 1 — Ontology (Cognitive Invariants)
The ontology layer injects domain knowledge and constraints into agent sessions before they execute. This ensures every agent operates within the project's semantic boundaries.
Ontology Structure
The ontology is defined in wave.yaml:
ontology:
telos: "Wave is a multi-agent pipeline orchestrator"
contexts:
- name: delivery
description: "Invariants for shipping features"
invariants:
- "A feature is not done until shipped pipelines use it"
- "Validation means the user-facing product changed"
- name: security
invariants:
- "Never commit secrets or credentials"
conventions:
commit_style: "conventional commits"
test_coverage: "all new code must have tests"Injection Flow
- The manifest loads the
ontologysection fromwave.yaml - Each step declares which contexts it needs via the
contexts:field - At execution time,
Ontology.RenderMarkdown(contextFilter)renders a filtered markdown section containing only the relevant contexts (internal/manifest/types.go:423-478) - The executor injects this rendered markdown into the adapter's system prompt (
internal/pipeline/executor.go:2964-3023) - The agent receives the invariants as part of its working context
Context Filtering
Steps can declare specific bounded contexts:
steps:
- id: implement
persona: craftsman
contexts: [delivery, security] # only these contexts are injectedIf a step references an undefined context, the executor logs a warning. If no contexts: field is specified, all contexts are injected.
Runtime Observability
- Injection is logged via
LogOntologyInject() - A
StateOntologyInjectevent is emitted for tracing
Layer 2 — Contracts (Structural Validation)
The contract layer validates step output structure before dependent steps proceed. Contracts catch malformed artifacts early, preventing wasted work downstream.
Contract Types
Wave supports 11 contract types:
| Type | Purpose |
|---|---|
json_schema | Validates output against a JSON Schema |
typescript_interface | Validates TypeScript compilation |
test_suite | Runs a test command |
markdown_spec | Validates markdown structure |
format | Checks output format |
non_empty_file | Verifies file exists and is non-empty |
llm_judge | LLM evaluates output against criteria |
source_diff | Verifies meaningful code changes were made |
agent_review | Delegates validation to another agent session |
event_contains | Validates specific pipeline events occurred |
spec_derived_test | Generates and runs tests from a specification |
The first 8 types are created via NewValidator() (internal/contract/contract.go:96-119). agent_review uses ValidateWithRunner() instead, as it requires an adapter runner. spec_derived_test uses ValidateSpecDerived(). event_contains is handled by ValidateEventContains() in the executor.
Hard vs. Soft Validation
- Hard (
must_pass: true, default): Failure blocks pipeline progression. The step transitions toretryingorfailed. - Soft (
must_pass: false): Failure logs a warning but does not block. Useful for advisory checks like linting.
See the Contracts Guide for configuration details and examples.
Layer 3 — Gates (Outcome Validation)
The gate layer provides human or automated checkpoints before the pipeline continues. Gates validate outcomes rather than structure.
Gate Types
| Type | Category | Purpose |
|---|---|---|
approval | Human | Pauses for reviewer decision (approve/revise/abort) |
timer | Automated | Waits for a specified duration |
pr_merge | Automated | Polls until a PR is merged or closed |
ci_pass | Automated | Polls until CI checks pass |
Gate execution is dispatched via the Execute switch in internal/pipeline/gate.go:77-88.
Fix-Loop Termination
When gates and conditional edges create fix-loops (implement → test → fix → test → ...), three safety mechanisms prevent runaway execution:
- Per-step
max_visits— Each step has a visit limit (default: 10). Exceeding it fails the pipeline. - Circuit breaker — If a step fails with the same error 3 consecutive times (
circuitBreakerWindow = 3), the loop terminates. Errors are normalized before comparison. (internal/pipeline/graph.go:425-452) - Graph-level
max_step_visits— An aggregate visit limit across all steps, enforced viaEffectiveMaxStepVisits(). (internal/pipeline/graph.go:100-104)
See the Gates Guide for configuration details and the Graph Loops guide for loop configuration.
V&V Pipeline Flow
See Also
- Validation Philosophy — Why validation matters and the incident that inspired this model
- Contracts Guide — Practical configuration for all contract types
- Gates Guide — Human approval and automated gate configuration
- Graph Loops — Fix-loop configuration and safety mechanisms