Validation boundary

This guide explains where a new validation check belongs: in the semantic validator or in the generation compatibility validator.

The two validators

AsyncApiValidator

Checks semantic conformance, reference integrity, advisories, and generator-wide supported-contract constraints.

This validator runs on every parsed contract, regardless of what the generator will produce. It answers: "Is this a valid AsyncAPI document that the generator can accept?"

GenerationInputCompatibilityValidator

Checks whether a specific requested output can consume the prepared contract.

This validator runs after the generation plan is created. It answers: "Can the selected generator capabilities produce the requested artifacts from this contract?"

Where to put a new check

Use this rule:

Generator-wide supported-contract constraints apply independently of the selected output target. Restrictions that exist only because a particular model, schema, language, or client backend was selected belong to generation compatibility validation.

Examples

Check Validator Reason
Channel has valid address format AsyncApiValidator Applies to all contracts regardless of output
Schema has valid JSON Schema structure AsyncApiValidator Applies to all contracts regardless of output
Native Protobuf input is available for Protobuf generation GenerationInputCompatibilityValidator Only applies when Protobuf generation is selected
Spring Kafka contract has valid method names GenerationInputCompatibilityValidator Only applies when Spring Kafka generation is selected
Avro schema has valid structure for Avro projection GenerationInputCompatibilityValidator Only applies when Avro projection is selected

For example, tuple-form and Boolean items are valid JSON Schema contract data, so a source generator that cannot represent them rejects them during generation compatibility validation. A scalar items value is a structural representation error and is rejected by the parser before semantic validation.

Decision flowchart

  1. Does the check apply to every contract the generator accepts, regardless of output target?
  2. YesAsyncApiValidator
  3. No → Continue to 2
  4. Does the check only matter because a specific generator capability was selected?
  5. YesGenerationInputCompatibilityValidator
  6. No → Continue to 3
  7. Does the check validate the contract against the AsyncAPI specification?
  8. YesAsyncApiValidator
  9. No → Consider whether the check belongs in the pipeline at all

Why this matters

  • Semantic validation catches problems early, before generation planning. Users see these errors even if they haven't configured a generator.
  • Compatibility validation catches problems late, after generation planning. Users see these errors only when their configuration requires capabilities the contract doesn't support.

Mixing these concerns makes it harder for contributors to understand where checks belong and harder for users to understand why a check failed.