Skip to content

Integrating a vendor component: a worked example

Acme Risk is a fictional vendor built for this experiment. Its jar supplies a risk calculation; the host is a principal trading desk. The integrator connects the component through a reference, and Fluxtion composes the supplier's nodes into the host processor.

This page accompanies Composing a system from supplier jars. The preserved experiment contains the supplier source, jars, feed, audit logs and independent calculation. The VaR comparisons below were re-run from that copy for this page. Generated-code excerpts and the build observations are attributed to the original prediction and results record; they are not a new generation run.

What you get

The supplier component becomes part of the host's event graph, with its own inputs, control service and audit trail. The experiment shows what that means:

  • Recorded — a sub-graph from a root reference. The reference discovered three internal vendor nodes, two vendor event types and one exported service, without the integrator wiring each internal node. See P5, P7, P11 and P12.
  • Re-verified — an audit order across the boundary. Reading the preserved quote record reproduces acmeQuoteFeed → acmeVarCalculator → acmeRiskEngine → riskLimitGuard: supplier processing followed by the host's response. See the genuine log and checker.
  • Recorded — shared events without adapter code. The host's MarketPrice implements the supplier's Quote interface, so the generated dispatcher calls both handlers. See P17's generated-code excerpt.

The component

The supplier source depends on Fluxtion's runtime. RiskEngine owns a VarCalculator, which reads QuoteFeed and PositionFeed. The root exposes the RiskControl service so its limit can be changed. The supplier knows its own event interfaces and calculation, not the host's graph.

RiskEngine — root, exported RiskControl service
  └─ VarCalculator
       ├─ QuoteFeed — prices and volatility
       └─ PositionFeed — positions

The two lines of wiring

Declare the supplier root, configure it, then reference it from your own node. This is the Spring excerpt preserved in the experiment's evidence record:

<bean id="acmeRisk" class="com.acmerisk.RiskEngine">
    <property name="varLimit" value="20000"/>
</bean>
<bean id="riskLimitGuard" class="com.example.myapp.node.RiskLimitGuard">
    <constructor-arg ref="acmeRisk"/>
</bean>

Never list a supplier's class in nodeBeans

Reference it from one of your own nodes instead. The starter writes skeleton classes for nodeBeans entries it cannot find source for. A class that exists only in a dependency jar looks like a class that does not exist yet, and the skeleton silently replaces it: the build stays green and the supplier's component is gone. This is the open dependency-shadowing issue, documented in the P4 reproduction.

Only the host node belongs in the starter's nodeBeans selection here. The compiler discovers the supplier's sub-graph through the reference. These discovered nodes use the supplier's NamedNode names; the bean id acmeRisk does not rename them.

What appeared

Preserved analyser view of the Acme Risk sub-graph, with Quote and RiskPosition inputs leading through the calculator and risk engine to riskLimitGuard

This is the experiment's original screenshot. It shows the topology and source at the selected cycle; it is not a claim that every visible node ran in that cycle.

The independently re-read genuine quote record lists this audit order:

acmeQuoteFeed → acmeVarCalculator → acmeRiskEngine → riskLimitGuard

There is a display limitation when the host's MarketPrice implements the supplier's Quote interface: both handlers dispatch, but the analyser does not draw the supertype route as part of the concrete event's path. TA-9 tracks it. Do not treat the highlighted topology path as a complete account of this dispatch. The composition page includes the abbreviated generated-handler excerpt from the record.

Control and configuration

The supplier exposes a getter and setter for varLimit. The P9 record quotes this line in generated code for the XML property above:

acmeRiskEngine.setVarLimit(20000.0);

RiskEngine also implements the exported RiskControl interface. The experiment's P12 uses flow.getExportedService(RiskControl.class) and calls setVarLimit to change the limit live. That harness is described in the record; it is separate from the CSV feed and was not re-run for this documentation change.

The shared-event pattern uses a handler typed on the supplier's Quote interface and a host event implementing it. It does not automatically transfer the host's position state into the vendor. The preserved experiment uses the vendor's own position feed; the host-state bridge was not implemented.

Checking the computation

The independent Python calculation reads the feed, computes volatility and VaR, then compares the result, breach state and alert state with the recorded nodes. It does not use the vendor's reported VaR as its expected value.

From a checkout of this repository:

cd docs/handoff/evidence/vendor-integration-2026-09-19
python3 check_var.py runs/risk-run3/audit.yaml
python3 check_var.py runs/risk-tampered/audit.yaml

The checker and preserved inputs reproduce:

Run Feed rows / audit records Mismatches Exit status
Genuine 11 / 11 0 0
Tampered 11 / 11 9 1, the expected rejection

The numerical tolerance is 1e-6, as defined in the checker. The expected failure on the tampered run matters: the comparison distinguishes the two recorded computations.

Upgrading safely

The preserved jars capture successive supplier implementations: an encapsulated build, a build with public nodes and stable names, and a build adding the interface-typed handler. Their roles and the host-upgrade checks are recorded in P6, P8, P13 and P17.

After changing a dependency, re-resolve the runtime classpath before launching: the experiment's run script used a cached .fluxtion/classpath, even though Maven had seen the new jar. Inspect the project's own setup and hosting runbooks for that refresh step.

Repeat both the host's existing scenarios and the independent supplier calculation after an upgrade. An unchanged host check does not establish the supplier's arithmetic. The full host validation harness is not in this evidence copy, so this page does not claim a new run of its historical host-validation totals.

When the jar is wrong

The P16 record describes rebuilding the supplier jar under the same filename with its risk constant zeroed. It records a green build and byte-identical XML, source and record hashes in the build receipt. Those receipt observations are preserved testimony from that run; the original before/after receipts are not included in this copy.

The recorded effect is directly checkable: the tampered log reports zero VaR, and the independent comparison above rejects 9 of its 11 records. Both logs still contain the supplier node sequence. The node trace describes which nodes logged and their order; it does not identify the supplier jar's bytes or establish the correctness of its arithmetic.

Checklists

For integrators

  • Declare the supplier root and reference it from your own node. Keep dependency-only classes out of nodeBeans while the dependency-shadowing issue remains open.
  • Refresh the runtime classpath after adding or changing a jar; do not assume a successful Maven build refreshed a launcher's cached classpath.
  • Read the supplier's naming contract. Discovered nodes need supplier-provided stable names; names are global, so coordinate them across suppliers.
  • Use the supplier's event interface where it fits. Decide separately how host state reaches the supplier; shared quote events do not supply position state.
  • Keep an independent calculation and rerun it with the host's scenarios after changes.
  • Check the audit log as well as the graph, retaining the supertype-route display caveat.

For suppliers

  • Make every node reachable from the root a public class, with a public wiring constructor matching its final fields, so generated code in another package can reconstruct it.
  • Implement NamedNode for stable, globally coordinated names; do not rely on generated suffixes.
  • Provide getters and setters for configurable properties. The getter-plus-setter path is the one exercised by the experiment; setter-only behaviour was not tested.
  • Publish public event types and interface-typed handlers so customers can supply events without writing adapters.
  • Follow the demonstrated node shape: EventLogNode for nodes that write audit values, and transient collections for runtime state. See the supplier source.

These checklists come from the experiment's predictions, results and limits. The experiment did not test dependency resolution by Maven coordinates, runtime-version conflicts, or two suppliers choosing the same node name.