Claus Ibsen created CAMEL-24693:
-----------------------------------

             Summary: EIP documentation YAML examples: validate at build time 
and ship as a per-EIP sample set in camel-catalog
                 Key: CAMEL-24693
                 URL: https://issues.apache.org/jira/browse/CAMEL-24693
             Project: Camel
          Issue Type: Improvement
          Components: camel-catalog, documentation
            Reporter: Claus Ibsen
            Assignee: Claus Ibsen


h3. Goal
Turn the YAML examples in the EIP documentation into a validated, per-EIP 
sample set that ships in camel-catalog, so tooling (Camel TUI editor and AI 
panel, camel-jbang-mcp, IDE plugins, Kaoto) can fetch a small, known-good YAML 
DSL sample for any EIP by name. Small local LLMs in particular fail on YAML DSL 
structure (where does onException go, what does a choice look like); a fetched 
sample fixes that class of error.

h3. What exists
{core/camel-core-engine/src/main/docs/modules/eips/pages/*.adoc}: 96 pages 
carry {[source,yaml]} blocks, 291 blocks in total, 280 of them complete route 
documents (a top-level list starting with route/from/beans/rest/...). Every 
page has at least one. All are in canonical YAML DSL form after the 2026-06 
audit.

Checked on 2026-09-11 with {camel validate yaml} (4.23.0-SNAPSHOT): *209 of 280 
validate, 71 do not.* Sample files are named {<page>-<n>.camel.yaml} where n is 
the block index on the page.

h3. Proposed pipeline (build time)
# Extract the {[source,yaml]} blocks from each EIP (and later component) doc 
page.
# Validate each against the YAML DSL JSON schema.
# Load each in a scratch CamelContext (parse/reify only, no start) to confirm 
the runtime accepts it.
# Package the samples that pass both under camel-catalog (for example 
{org/apache/camel/catalog/samples/eips/<eip>-<n>.yaml}) and expose them via a 
{CamelCatalog} API (e.g. {eipSamples(name)}), a camel-jbang-mcp tool and a TUI 
MCP tool.
# Fail the build (or report) when a doc example fails either check, so doc 
examples stay correct; report schema-versus-runtime disagreements separately, 
they are schema bugs.

h3. The 71 samples that fail schema validation today
Some are genuine doc errors (e.g. circuitBreaker: onFallback placed inside the 
circuit breaker steps also fails at runtime; the loadBalancer pages use 
{failoverLoadBalancer: {}} as a step). Many are the schema being stricter than 
the runtime about scalars ({parallelProcessing: "true"} and {timePeriodMillis: 
10000} both start fine with {camel run}); those are tracked in the companion 
schema issue and the docs should still be normalised to the schema's preferred 
form. The oneOf cases (marshal, unmarshal, resequence) need a look at the 
schema.

*Scalar type mismatch (schema stricter than runtime; see the companion schema 
issue)* (41):
{noformat}
claimCheck-4.camel.yaml:                
/0/route/from/steps/3/setHeader/expression/constant: integer found, string 
expected
log-8.camel.yaml:               /0/route/logMask: string found, boolean expected
loop-1.camel.yaml:              
/0/route/from/steps/0/loop/expression/constant/expression: integer found, 
string expected
loop-4.camel.yaml:              /0/route/from/steps/0/loop/copy: string found, 
boolean expected
loop-5.camel.yaml:              /0/route/from/steps/0/loop/doWhile: string 
found, boolean expected
message-history-1.camel.yaml:           /0/route/messageHistory: string found, 
boolean expected
message-history-2.camel.yaml:           /0/route/messageHistory: string found, 
boolean expected
multicast-2.camel.yaml:                 
/0/route/from/steps/0/multicast/parallelProcessing: string found, boolean 
expected
multicast-3.camel.yaml:                 
/0/route/from/steps/0/multicast/parallelProcessing: string found, boolean 
expected
multicast-4.camel.yaml:                 
/0/route/from/steps/0/multicast/parallelProcessing: string found, boolean 
expected
multicast-5.camel.yaml:                 
/0/route/from/steps/0/multicast/stopOnException: string found, boolean expected
pollEnrich-1.camel.yaml:                
/0/route/from/steps/0/pollEnrich/timeout: integer found, string expected
recipientList-4.camel.yaml:             
/0/route/from/steps/0/recipientList/parallelProcessing: string found, boolean 
expected
recipientList-5.camel.yaml:             
/0/route/from/steps/0/recipientList/stopOnException: string found, boolean 
expected
recipientList-6.camel.yaml:             
/0/route/from/steps/0/recipientList/ignoreInvalidEndpoints: string found, 
boolean expected
rollback-2.camel.yaml:          
/0/route/from/steps/0/choice/when/0/steps/0/rollback/markRollbackOnly: string 
found, boolean expected
routingSlip-2.camel.yaml:               
/0/route/from/steps/0/routingSlip/ignoreInvalidEndpoints: string found, boolean 
expected
saga-7.camel.yaml:              /1/route/from/steps/0/saga/option: object 
found, array expected
scatter-gather-2.camel.yaml:            
/1/route/from/steps/0/aggregate/completionTimeout: integer found, string 
expected
split-10.camel.yaml:            /0/route/from/steps/0/split/streaming: string 
found, boolean expected
split-11.camel.yaml:            /0/route/from/steps/0/split/streaming: string 
found, boolean expected
split-12.camel.yaml:            /0/route/from/steps/0/split/streaming: string 
found, boolean expected
split-13.camel.yaml:            /0/route/from/steps/0/split/streaming: string 
found, boolean expected
split-15.camel.yaml:            /0/route/from/steps/0/split/group: string 
found, number expected
split-16.camel.yaml:            /0/route/from/steps/0/split/maxFailedRecords: 
string found, number expected
split-17.camel.yaml:            /0/route/from/steps/0/split/errorThreshold: 
string found, number expected
split-20.camel.yaml:            /0/route/from/steps/0/split/stopOnException: 
string found, boolean expected
split-21.camel.yaml:            /0/route/from/steps/1/split/shareUnitOfWork: 
string found, boolean expected
split-5.camel.yaml:             /0/route/from/steps/0/split/parallelProcessing: 
string found, boolean expected
split-6.camel.yaml:             /0/route/from/steps/0/split/parallelProcessing: 
string found, boolean expected
split-8.camel.yaml:             /0/route/from/steps/0/split/streaming: string 
found, boolean expected
split-9.camel.yaml:             /0/route/from/steps/0/split/streaming: string 
found, boolean expected
throttle-1.camel.yaml:          
/0/route/from/steps/0/throttle/timePeriodMillis: integer found, string expected
throttle-2.camel.yaml:          
/0/route/from/steps/0/throttle/expression/constant/expression: integer found, 
string expected
throttle-3.camel.yaml:          
/0/route/from/steps/0/throttle/timePeriodMillis: integer found, string expected
throttle-4.camel.yaml:          /0/route/from/steps/0/throttle/asyncDelayed: 
string found, boolean expected
throttle-5.camel.yaml:          /0/route/from/steps/0/throttle/rejectExecution: 
string found, boolean expected
throttle-6.camel.yaml:          
/0/route/from/steps/0/throttle/expression/constant/expression: integer found, 
string expected
throttle-7.camel.yaml:          
/0/route/from/steps/0/throttle/expression/constant/expression: integer found, 
string expected
unmarshal-2.camel.yaml:                 
/0/route/from/steps/0/unmarshal/allowNullBody: string found, boolean expected
wireTap-1.camel.yaml:           
/1/route/from/steps/0/delay/expression/constant/expression: integer found, 
string expected
{{noformat}}

*Property not in schema (doc example or schema gap; needs a runtime check 
each)* (20):
{noformat}
circuitBreaker-1.camel.yaml:            
/0/route/from/steps/0/circuitBreaker/steps/1: property 'onFallback' is not 
defined in the schema and the schema does not allow additional properties
customLoadBalancer-1.camel.yaml:                
/0/route/from/steps/0/loadBalance/steps/0: property 'customLoadBalancer' is not 
defined in the schema and the schema does not allow additional properties
doTry-2.camel.yaml:             
/0/route/from/steps/0/doTry/steps/2/doCatch/steps/0: property 'onWhen' is not 
defined in the schema and the schema does not allow additional properties
failoverLoadBalancer-1.camel.yaml:              
/0/route/from/steps/0/loadBalance/steps/0: property 'failoverLoadBalancer' is 
not defined in the schema and the schema does not allow additional properties
failoverLoadBalancer-2.camel.yaml:              
/0/route/from/steps/0/loadBalance/steps/0: property 'failoverLoadBalancer' is 
not defined in the schema and the schema does not allow additional properties
failoverLoadBalancer-3.camel.yaml:              
/0/route/from/steps/0/loadBalance/steps/0: property 'failoverLoadBalancer' is 
not defined in the schema and the schema does not allow additional properties
failoverLoadBalancer-4.camel.yaml:              
/0/route/from/steps/0/loadBalance/steps/0: property 'failoverLoadBalancer' is 
not defined in the schema and the schema does not allow additional properties
fault-tolerance-1.camel.yaml:           
/0/route/from/steps/0/circuitBreaker/steps/1: property 'onFallback' is not 
defined in the schema and the schema does not allow additional properties
fault-tolerance-2.camel.yaml:           
/0/route/from/steps/0/circuitBreaker/steps/0: property 
'faultToleranceConfiguration' is not defined in the schema and the schema does 
not allow additional properties
fault-tolerance-3.camel.yaml:           /0/route/from/steps/1/circuitBreaker: 
property 'inheritErrorHandler' is not defined in the schema and the schema does 
not allow additional properties
keyValueRepository-13.camel.yaml:               /0/from/steps/0/aggregate: 
property 'strategyRef' is not defined in the schema and the schema does not 
allow additional properties
randomLoadBalancer-1.camel.yaml:                
/0/route/from/steps/0/loadBalance/steps/0: property 'randomLoadBalancer' is not 
defined in the schema and the schema does not allow additional properties
resilience4j-1.camel.yaml:              
/0/route/from/steps/0/circuitBreaker/steps/1: property 'onFallback' is not 
defined in the schema and the schema does not allow additional properties
resilience4j-2.camel.yaml:              
/0/route/from/steps/0/circuitBreaker/steps/0: property 
'resilience4jConfiguration' is not defined in the schema and the schema does 
not allow additional properties
resilience4j-3.camel.yaml:              
/0/route/from/steps/0/circuitBreaker/steps/0: property 
'resilience4jConfiguration' is not defined in the schema and the schema does 
not allow additional properties
resilience4j-4.camel.yaml:              /0/route/from/steps/1/circuitBreaker: 
property 'inheritErrorHandler' is not defined in the schema and the schema does 
not allow additional properties
roundRobinLoadBalancer-1.camel.yaml:            
/0/route/from/steps/0/loadBalance/steps/0: property 'roundRobinLoadBalancer' is 
not defined in the schema and the schema does not allow additional properties
stickyLoadBalancer-1.camel.yaml:                
/0/route/from/steps/0/loadBalance/steps/0: property 'stickyLoadBalancer' is not 
defined in the schema and the schema does not allow additional properties
topicLoadBalancer-1.camel.yaml:                 
/0/route/from/steps/0/loadBalance/steps/0: property 'topicLoadBalancer' is not 
defined in the schema and the schema does not allow additional properties
weightedLoadBalancer-1.camel.yaml:              
/0/route/from/steps/0/loadBalance/steps/0: property 'weightedLoadBalancer' is 
not defined in the schema and the schema does not allow additional properties
{{noformat}}

*oneOf ambiguity in the schema* (10):
{noformat}
marshal-1.camel.yaml:           /0/route/from/steps/0/unmarshal: must be valid 
to one and only one schema, but 0 are valid
resequence-10.camel.yaml:               /0/route/from/steps/0/resequence: must 
be valid to one and only one schema, but 2 are valid with indexes '1, 2'
resequence-11.camel.yaml:               /0/route/from/steps/0/resequence: must 
be valid to one and only one schema, but 2 are valid with indexes '1, 2'
resequence-2.camel.yaml:                /0/route/from/steps/0/resequence: must 
be valid to one and only one schema, but 2 are valid with indexes '1, 2'
resequence-4.camel.yaml:                /0/route/from/steps/0/resequence: must 
be valid to one and only one schema, but 2 are valid with indexes '1, 2'
resequence-5.camel.yaml:                /0/route/from/steps/0/resequence: must 
be valid to one and only one schema, but 2 are valid with indexes '1, 2'
resequence-6.camel.yaml:                /0/route/from/steps/0/resequence: must 
be valid to one and only one schema, but 2 are valid with indexes '1, 2'
resequence-7.camel.yaml:                /0/route/from/steps/0/resequence: must 
be valid to one and only one schema, but 2 are valid with indexes '1, 2'
resequence-9.camel.yaml:                /0/route/from/steps/0/resequence: must 
be valid to one and only one schema, but 2 are valid with indexes '1, 2'
unmarshal-1.camel.yaml:                 /0/route/from/steps/0/unmarshal: must 
be valid to one and only one schema, but 0 are valid
{{noformat}}

h3. Origin
Found on 2026-09-11 while benchmarking AI-assisted editing in the Camel TUI: a 
local model could not learn YAML DSL structure from the option-level catalog 
docs alone. Related: CAMEL-23774 (recipes catalog), CAMEL-24362 (YAML DSL 
completion model), CAMEL-24692 (simple validator placeholder bug).



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to