Apache Camel Compliance Gateway (compliance-camel, :8181)
Scope: stateless NATS protocol-translation gateway between agent-bff (brain) and external APIs (hands) — YAML routes + Java beans.
Status (2026-11-08): Camel Quarkus 3.8 gateway with YAML auto-discovery and queue-group consumers (source: docker/compliance/camel/pom.xml; AGENTS.md).
Blueprint sources: docker/compliance/camel/pom.xml (artifact/deps), docker/compliance/camel/routes/.yaml (from/queue/to verified per file), docker/compliance/camel/src/main/java/com/sovereignos/camel/claimgen/.java (bean javadocs), apps/agent-bff/src/compliance-api-dispatcher.js + external-gate-camel-adapter.js (dispatch logic), AGENTS.md (metaphor/topology, deployment profile).
1. Gateway role (paragraph)
The gateway is a stateless protocol-translation gateway: it consumes NATS egress.camel., translates JSON to SOAP/XML/EDI, executes HTTP/mTLS, and publishes responses to ingress.camel. (source: docker/compliance/camel/pom.xml description). The container at :8181 implements the Camel hands metaphor where agent-bff (brain) dispatches commands via NATS and Camel reaches external APIs with the right protocol and certificates (source: AGENTS.md). Auth, rate limiting, PoCE recording, and FSM state stay in agent-bff before dispatch; Camel translates only and does not authorize (source: AGENTS.md). Route definitions are external YAML files under docker/compliance/camel/routes/ mounted read-only at /opt/camel/routes/ and auto-discovered as *.yaml at startup, so no rebuild is needed to add or modify routes (source: AGENTS.md). Horizontal scaling uses NATS queue groups per route (e.g. camel-cbam-workers), enabling round-robin across replicas (source: AGENTS.md). The gateway runs behind the compliance Docker profile and is not started by default (source: AGENTS.md).
2. One row per route file (from YAML contents — verified)
Route files on disk (source: directory listing of docker/compliance/camel/routes/): 60+ YAMLs. The rows below cover the compliance family named in AGENTS.md plus the claimgen family; column values are taken from each YAML's from:/to: lines, not from the catalog prose. "Target" is the literal to: URI in that file (all currently https://httpbin.org/post or http://httpbin.org/post echo placeholders); "certs" is what the YAML itself declares (none declare mTLS client certs — per-org certs are described only in AGENTS.md prose).
| Route file (id) | Subject (from:) + queue | Protocol / target (to:) | Certs (in YAML) | Error / response subject |
|---|---|---|---|---|
cbam-route.yaml (egress.camel.eu.cbam) | nats:egress.camel.eu.cbam, queue camel-cbam-workers | JSON unmarshal/marshal; https://httpbin.org/post POST, TTL 60000 | none declared in YAML | nats:ingress.camel.eu.cbam.response |
tancis-route.yaml (egress.camel.tz.tancis) | nats:egress.camel.tz.tancis, queue camel-tancis-workers | JSON unmarshal/marshal; https://httpbin.org/post POST, TTL 60000 | none declared in YAML | nats:ingress.camel.tz.tancis.response |
eudris-route.yaml (egress.camel.eu.eudris) | nats:egress.camel.eu.eudris, queue camel-eudris-workers | JSON unmarshal/marshal; https://httpbin.org/post POST, TTL 60000 | none declared in YAML | nats:ingress.camel.eu.eudris.response |
mtls-route.yaml (egress.camel.eu.cbam mTLS variant) | nats:egress.camel.eu.cbam, queue camel-mtls-workers | JSON unmarshal/marshal; https://httpbin.org/post POST, TTL 60000 | none declared in YAML (mTLS per-org certs described in AGENTS.md prose, not in YAML) | nats:ingress.camel.eu.response |
| generic-outbound-route.yaml | nats:egress.camel.generic.> (comment: must NOT subscribe to egress.camel.> — steals jetstream/deliver/MRV routes), queue camel-generic-workers | JSON unmarshal/marshal; http://httpbin.org/post POST, TTL 30000 | none declared in YAML | nats:ingress.camel.test.response |
| claimgen-intake-extgate-routes.yaml (provider upsert) | nats:egress.camel.intake.provider.upsert, queue camel-capsrc-provider-intake | bean providerCapabilityUpsertMap (no external HTTP target in YAML) | none | nats:claims.intake.v1.dlq on ConfigTrackValidationException |
| claimgen-intake-extgate-routes.yaml (processing intake) | nats:egress.camel.intake.processing.create, queue camel-claimgen-intake | bean claimgenIntakeFieldMap (no external HTTP target in YAML) | none | nats:claims.intake.v1.dlq on ConfigTrackValidationException |
| claimgen-intake-extgate-routes.yaml (external gate) | nats:egress.camel.extgate.invoke, queue camel-claimgen-extgate | bean extgateVerdictRouter -> nats:ingress.camel.extgate.response | none | nats:claims.intake.v1.dlq on ConfigTrackValidationException |
All three claimgen routes stop unless env CLAIMGEN_CAMEL=1 and log that they are disabled otherwise (source: docker/compliance/camel/routes/claimgen-intake-extgate-routes.yaml). Catalog cross-check (AGENTS.md prose, not literal YAML targets): cbam-route (egress.camel.eu.cbam -> EU CBAM MRV Portal, SOAP 1.2), tancis-route (egress.camel.tz.tancis -> TRA TANCIS, SOAP 1.1 + WS-Security), eudris-route (egress.camel.eu.eudris -> TRACES NT, SOAP 1.2), mtls-route (egress.camel.eu.> / egress.camel.tz.> with per-org certs), generic-outbound (egress.camel.>) (source: AGENTS.md). Per-route .failed subjects (e.g. ingress.camel.eu.cbam.failed, ingress.camel.tz.tancis.failed, ingress.camel.eu.eudris.failed) and generic timeout ingress.camel.generic.error are documented in AGENTS.md; the literal YAMLs read for this map contain no onException/.failed step (verified above) — only the claimgen file declares nats:claims.intake.v1.dlq.
3. Stack + Java source census (pom.xml + src tree)
Java stack is Quarkus 3.8 + Camel Quarkus with jnats 2.20.2 and S2 geometry loaded for the s2: component; runtime deps are Maven 21, UTF-8, quarkus-maven-plugin 3.8.0 (source: docker/compliance/camel/pom.xml). Artifact names exactly as declared (source: docker/compliance/camel/pom.xml): camel-quarkus-core, camel-quarkus-yaml-dsl, camel-quarkus-bean, camel-quarkus-nats, jnats (io.nats 2.20.2), camel-quarkus-http, camel-quarkus-platform-http, camel-quarkus-jackson, camel-quarkus-jsonpath, camel-quarkus-jq, camel-quarkus-direct, camel-quarkus-soap, camel-quarkus-bindy, s2-geometry-library-java (io.sgr 1.0.1), quarkus-smallrye-health, quarkus-micrometer-registry-prometheus, quarkus-logging-json; test-scope: quarkus-junit5, camel-quarkus-mock.
Java source tree (source: file listing under docker/compliance/camel/src/main/java/com/sovereignos/camel/):
claimgen/(pre-commit gate family for this map):ClaimgenIntakeFieldMap.java,
ProviderCapabilityUpsertMap.java, ExtgateVerdictRouter.java, IntakeMapSupport.java.
config/(shared processors):CorrelationIdInjector.java,CorrelationIdExtractor.java,
CrossRealmHopProof.java, CrossRealmHopRestore.java, DeadLetterHandler.java, MtlsSslContextFactory.java (CDI @Named("mtlsContext") cert loading), NatsConnectionFactory.java, SurrealDbTxProcessor.java, TruthEdgeFormulaEvaluator.java.
configtrack/(track bus consumers):ConfigTrackCellState,ConfigTrackCountersignPublisher,
ConfigTrackDlqEnricher, ConfigTrackEnvelopeValidator, ConfigTrackEventTypeRegistry, ConfigTrackOfferCapture, ConfigTrackOutboxRelayGuard, ConfigTrackReofferConsumer, ConfigTrackReportFanIn, ConfigTrackRollupEngine, ConfigTrackRollupPublisher, ConfigTrackSlaBreachPublisher, ConfigTrackThreatConsumer, ConfigTrackThreatQuarantineRegistry, ConfigTrackValidationException, ConfigTrackVoyage, ConfigTrackVoyageStore.
criteria/(criteria normalizers):CandidateStateCriteriaNormalizer,
CriteriaNormalizeSupport, InventoryTickCriteriaNormalizer, LifelongEntityChangeCriteriaNormalizer, LifelongEntityStateFacetWatchProcessor, OpsDispatchCriteriaNormalizer, SourcingOfferCriteriaNormalizer, SourcingRequirementCriteriaNormalizer, TruthGraphMutationCriteriaNormalizer, TruthGraphStateFacetWatchProcessor.
component/(Camel component families: base, bbs, claim, cns, fsm, poce, s2, surrealdb, trait,
truthgraph, uon — each with Component/Endpoint/Producer plus SurrealDb variants).
- plus
accum/,deliver/,gitforge/,jetstream/(episode stores, delivery beans,
webhook HMAC verifier, JetStream ensure/release beans).
4. Claimgen bean roles in detail
Bean 1 — ClaimgenIntakeFieldMap (CLAIMGEN-07 processing intake). Executes processing_create field maps (FNOL intake): consumes egress.camel.intake.processing.create envelopes { event_id, map_id, payload, correlation_id }, applies the declarative map from lookup.camel.intake.maps.v1 (NATS KV), validates the create contract, and creates the processing claim via fn::claim_processing::create_claim (s282) over the Surreal HTTP /sql endpoint (NS africa / DB community_os, default base http://host.docker.internal:8000) (source: docker/compliance/camel/src/main/java/com/sovereignos/camel/claimgen/ClaimgenIntakeFieldMap.java; route: docker/compliance/camel/routes/claimgen-intake-extgate-routes.yaml). Fail closed: unknown map / missing field / Surreal down / FN missing all throw (to claims.intake.v1.dlq via onException) — never a silently-dropped intake and never an invented claim; the bean comments note the Surreal function must be deployed or its absence surfaces as a DLQ'd Surreal error, not fake success (source: same bean). Exchange properties claimgen_map_id/claimgen_event_id feed the route log line (source: docker/compliance/camel/routes/claimgen-intake-extgate-routes.yaml).
Bean 2 — ProviderCapabilityUpsertMap (CAPSRC-10 provider intake). Same template family, different target: consumes egress.camel.intake.provider.upsert, applies the declarative provider_upsert map from lookup.camel.intake.maps.v1, validates the upsert contract, and upserts the provider profile via fn::provider::upsert_profile (s365) (source: docker/compliance/camel/src/main/java/com/sovereignos/camel/claimgen/ProviderCapabilityUpsertMap.java). Fail closed on unknown map / bad role_type / Surreal down / FN missing (all throw to claims.intake.v1.dlq); never a silently-dropped intake and never an invented provider. The BFF Soft desk (/v1/provider-capability/intake) publishes the envelope; this bean executes it (source: same bean; intake route: apps/agent-bff/src/provider-capability-intake.js via docs/commercialization/39_CAPABILITY_SUPPLY_SOURCING_BACKLOG.md CAPSRC-10).
Bean 3 — ExtgateVerdictRouter (CLAIMGEN-07 external-gate). Consumes the BFF external-gate request { event_id, adapter_class, purpose, claim_id, claim_type, actor_id, correlation_id, evidence } and produces { event_id, adapter_class, verdict, reason, correlation_id } for ingress.camel.extgate.response (source: docker/compliance/camel/src/main/java/com/sovereignos/camel/claimgen/ExtgateVerdictRouter.java). Closed vocabulary only — identity / content / sanctions / quota / customs (doc 43 S6 protocol classes, never countries); unknown adapter_class throws to DLQ; known-but-unwired class answers REFUSE naming the unwired adapter so the BFF fails closed (source: same bean). Guard: all three routes share the CLAIMGEN_CAMEL=1 gate (route choice on ${env:CLAIMGEN_CAMEL} != '1' -> log + stop), and all three onException blocks catch com.sovereignos.camel.configtrack.ConfigTrackValidationException into nats:claims.intake.v1.dlq (source: docker/compliance/camel/routes/claimgen-intake-extgate-routes.yaml). The BFF adapter external-gate-camel-adapter.js carries the verdict call to egress.camel.extgate.invoke -> ingress.camel.extgate.response, is jurisdiction-agnostic (protocol classes, never country names), and is fail-closed: adapter down + critical stage -> invent_refuse; non-critical without fail_mode=refuse -> warn-allow (source: apps/agent-bff/src/external-gate-camel-adapter.js).
5. Dispatcher decision table (payload rule -> path)
BFF retains URL validation, auth resolution, rate limiting, and HMAC signing; Camel handles protocol translation, HTTP dispatch, and correlation-ID mapping (source: apps/agent-bff/src/compliance-api-dispatcher.js header; AGENTS.md). SSRF guard blocks localhost/private prefixes (10., 172.16., 192.168., fc/fd/fe80, *.local) and cloud metadata hosts before any dispatch (source: apps/agent-bff/src/compliance-api-dispatcher.js). PoCE bridge is optional/best-effort: when governance_path_spec_id is present the dispatcher starts/records/finalizes a PoCE session around the Camel call; PoCE failures never block dispatch (source: AGENTS.md PoCE Bridge CML-3.3; dispatcher: startCamelPoceSession path).
| Payload rule (as coded) | Path (as coded) |
|---|---|
JSON, no camel_route, use_camel not true (shouldRouteViaCamel=false) | Direct HTTP dispatch (backward compatible) |
JSON with explicit camel_route | Camel egress.camel.<route> via routeViaCamel |
JSON with use_camel=true (derived route) | Camel egress.camel.<derived> |
protocol soap-xml or xml (any camel_route/use_camel) | Camel egress.camel.<derived>; body pre-translated to SOAP envelope (buildSoapEnvelope, contentType application/soap+xml) |
| derived route null (cannot determine) | Fall back to direct HTTP (executeHttpRequest) |
Source for the rule: const isSoapXml = protocol === 'soap-xml' || protocol === 'xml'; const shouldRouteViaCamel = explicitCamelRoute || isSoapXml || forceCamel === true; (source: apps/agent-bff/src/compliance-api-dispatcher.js, routing strategy block). Hostname derivation deriveCamelRoute (source: apps/agent-bff/src/compliance-api-dispatcher.js): cbam / ec.europa.eu -> eu.cbam; tancis / tra.go.tz -> tz.tancis; traces / ec.europa.eu -> eu.traces; eudris -> eu.eudris; otherwise generic.<sanitized_hostname>.
6. Honest limits
- No authorization in Camel: auth, rate limiting, SSRF protection, PoCE recording, and FSM
state all remain in the Sovereign OS BFF layer (source: AGENTS.md).
- Stateless: no persistent state, no SurrealDB access, no PoCE session creation inside Camel;
each request is a NATS subscription plus response publish (source: AGENTS.md). (The claimgen beans do call Surreal over HTTP for fn::* writes — see S4 — which is the declared exception to the stateless prose in AGENTS.md; noted here so the two source statements are not confused.)
- DLQ/error subjects and timeouts: per-route
*.failedsubjects (e.g.
ingress.camel.eu.cbam.failed) and generic timeout ingress.camel.generic.error are documented in AGENTS.md; the literal YAMLs read show only nats:claims.intake.v1.dlq for intake validation and plain response subjects otherwise (see S2).
- Echo placeholders: the cbam/tancis/eudris/mtls/generic YAMLs POST to
https://httpbin.org/post (http://httpbin.org/post for generic), so the external-portal URLs in the AGENTS.md catalog are not the literal routed URLs in those files (source: docker/compliance/camel/routes/cbam-route.yaml, tancis-route.yaml, eudris-route.yaml, mtls-route.yaml, generic-outbound-route.yaml).
- No external integration wired for any extgate class yet: the verdict router answers REFUSE by
design until a real endpoint lands (source: docker/compliance/camel/src/main/java/com/sovereignos/camel/claimgen/ExtgateVerdictRouter.java).
- No TRACES-specific route YAML was read alongside cbam/tancis/eudris in this set; traces
handling is described in the AGENTS.md catalog and dispatcher derivation (source: AGENTS.md; apps/agent-bff/src/compliance-api-dispatcher.js).