Skip to content

Fusion-to-ADI Integration Pattern

Status & scope

  • Status: DRAFT
  • Layer: integration boundary (fusion → ADI/DES)
  • Date: 2026-04-30
  • Author: Chris Yonclas
  • Companion specs: wire-message-families, dissent (MachineDissent), axonis-lens SPEC-19 (incremental updates)
  • Supersedes (in part): the fusion-integration design discussion; becomes the architectural reference that its sub-tickets implement.

1. Purpose

Define the integration pattern by which any lens engine — Parallax (Identity Lens / entity resolution), Prism (Cost Lens / Decision Lens / source-localization), or future engines — emits results into the ADI workflow (Monitor → Investigate → Decide → Attest → Act).

The architectural insight: all lens engines collapse to the same four-contract integration pattern. Engine differs. Lens YAML differs. Output content differs. Integration pattern is identical.


2. The Architectural Insight

Today, Parallax produces entity-match results and Cortex emits them as Signals. The proposed Cost Lens (Prism) family produces threat surfaces, route corridors, observation windows, and action timing. Both must flow through the same ADI pipeline so that:

  • One Beacon dispatcher renders any signal regardless of which engine produced it
  • One Cortex lens runtime dispatches lens YAMLs to the right engine
  • One evidence-block schema captures pedigree across engines (replay determinism, FED-SPEC-02)
  • One signal schema lets policy/triggers fire without engine-specific branches

This is not a refactor. It is the platform pattern that lets ADI grow without coupling to engine implementations.


3. The Four Contracts

3.1 Signal

The "header" object — what hits the Monitor queue and triggers downstream actions.

Signal:
  signal_id: ULID
  signal_type: str               # e.g. "fusion_identity_match", "threat_threshold_crossed",
                                 #      "corridor_change", "observation_window_open"
  severity: enum(low, medium, high, critical)
  lens_id: str                   # which lens produced this
  lens_version: semver
  score: float                   # composite score / confidence / risk magnitude
  summary: str                   # one-line human-readable
  evidence_block_ref: BlockRef   # pointer to pedigree
  view_hint: ViewHint            # how to render (see §3.3)
  timestamp_utc: ISO8601
  scope: { object_types: [...], geographic: str, time_window: str }
  signing: { signer_id, signature, query_hash }

Key invariant: the signal does NOT contain raw data. It contains a pointer to evidence (evidence_block_ref) and a hint for rendering (view_hint). Raw data stays inside the block, behind ABAC.

3.2 Evidence Block

The "why" object — full pedigree, replay-deterministic, frozen-once-written.

Existing schema (extend, don't replace):

EvidenceBlock:
  block_id: ULID
  lens_id, lens_version
  inputs: { node_a_query_hash, node_b_query_hash, ... }   # what data was queried
  derivation: { transforms, normalisations, blocking, scoring }  # how
  output:                                                 # what
    type: enum(entity_match, surface_grid, route, window, anomaly, ...)
    payload: <type-specific>                              # see §4 use cases
  view_hint: ViewHint                                     # NEW — see §3.3
  signing: { signer_id, signature, frozen_at }
  query_hash: SHA-256                                     # canonical-form hash for replay

view_hint is added to the block so an investigator viewing the block in isolation (without going through the signal) still gets the right rendering.

3.3 ViewHint

NEW contract — small, declarative, dispatched on by Beacon.

ViewHint:
  component: str                  # canonical component name — see §3.4
  layout_type: enum(map_layer, table, timeline, gantt, kpi, choropleth,
                    cluster_card, polyline, heatmap, evidence_panel,
                    geo_overlay_with_uncertainty, ...)
  color_scale: optional<str>      # named scale from a palette registry
  time_axis: optional<{ start, end, bucket }>
  geographic_bounds: optional<bbox>
  primary_field: optional<str>    # which output field drives the visual
  display_options: dict           # component-specific tunables

ViewHint is advisory, not authoritative — Beacon can substitute or fall back. But if Cortex emits a hint that Beacon doesn't understand, the rendering should degrade gracefully (table view as default).

3.4 Component

Beacon's UI widgets. Contract is the canonical name registered in a Component Registry. New components added over time; old components survive lens-YAML changes because the lens names the component, not the implementation.

Component (canonical name) Renders Status
cluster_card Entity-match clusters with per-field scores exists
evidence_panel Frozen evidence block with derivation tree exists
kpi_tile Single-number KPI with trend exists
geo_temporal_viewer Multi-layer map with time slider exists
signal_feed Time-ordered signal stream exists
gantt Time-window / scheduling visualization new
choropleth Heatmap on geographic grid new
polyline_with_cost Route line with per-segment cost coloring new
geo_overlay_with_uncertainty Source location + confidence ellipse new
lens_editor Form-based or YAML-based lens editor new (Phase 4)

4. Use Case Walk — Same Pattern, Different Content

Use case Engine Signal signal_type Block output.type ViewHint component
VRS screening match Parallax (Identity) fusion_identity_match entity_match cluster_card
Multi-INT source attribution Parallax + Prism (Decision) source_detected localized_source geo_overlay_with_uncertainty
Threat surface high-cell Prism (Cost: threat) threat_threshold_crossed surface_grid choropleth
Route corridor change Prism (Cost: traversal) corridor_change route polyline_with_cost
Observation window open Prism (Cost: observation) observation_window_open time_window gantt
Anomaly via incremental fusion Parallax (incremental) cluster_split_dissent machine_dissent (SPEC-30) evidence_panel
N-party Disney retention match Parallax multi_brand_customer_aligned entity_cluster_n_party cluster_card

The pattern holds for all of these. Adding a new lens type means: 1. Define what the engine emits as output.payload 2. Pick or add a view_hint.component 3. (If needed) build the new component in Beacon 4. Lens YAML names everything

Nothing in Cortex's signal/block emitter changes per lens. Nothing in Beacon's dispatcher changes per lens.


5. What Changes in Cortex

Component New / Existing Description
Lens runtime dispatcher NEW Reads lens_type from YAML; routes to parallax.ops.fusion (entity_resolution) or prism.{traversal,threat,observation,temporal} or future engines. Single MCP tool: execute_lens(lens_id, inputs).
Signal/Block emitter EXTEND Existing create_block() and create_signal() paths gain view_hint field on output; populated by the engine adapter.
Lens registry NEW (small) UDS-backed store of validated lens YAMLs — versioned, immutable once frozen, replay-deterministic. CRUD via MCP tools.
Lens validator MCP tool NEW Validates a YAML against the lens schema; returns parse errors structured for the UI editor. Reusable by tier-0 lens editor.
Engine adapters EXTEND / NEW parallax_adapter (extends existing path); prism_adapter (new — even partial Prism plugs in). Each adapter knows how to map engine output → output.payload + view_hint.
Trigger / policy engine EXTEND Existing signal-policy hook fires on filter rules (signal_type, severity, score >= X). Already in place; just needs to consume the unified signal schema.

Not changing: UDS, ABAC, Cortex MCP tool count (just adding ~5 new tools). Beacon UI patterns. Pack format.


6. What Changes in Beacon

Component New / Existing Description
ViewHint dispatcher NEW (~50 LOC) Given a Signal or Block, look at view_hint.component, route to that component. Fallback to evidence_panel table view for unknown hints.
Component library EXTEND Most components exist (geo_temporal viewer, evidence panel, KPI tiles, COA cards, cluster card). NEW: gantt, choropleth, polyline_with_cost, geo_overlay_with_uncertainty.
Lens result panel (S-NEW per CLAUDE.md) NEW Already in Jocelyn's queue — fits this pattern. The panel reads view_hint to decide layout.
Lens editor UI NEW (Phase 4 — see §8) Form-based editor; uses the Cortex lens validator MCP for live validation.

Not changing: Beacon's existing block-execution path (the execute_monitor_block call). NgRx store shape. Pack consumption. The engine work is orthogonal — Beacon just consumes the unified contracts.


7. What Changes in Prism (axonis-lens)

Component Status
Engine Early — axonis-lens repo, four lens types defined (Traversal, Threat, Observation, Temporal); lens YAML schema + parser shipping
ADI integration None today — but with this spec, integration is a Cortex adapter, not Prism work
MCP tool dispatch Inherits from §5's Lens runtime dispatcher — Prism plugs in as another adapter
Output → view_hint mapping NEW — per Prism lens type, define which view_hint.component to emit

Prism doesn't need to know about ADI. It produces typed output (route, surface, window). The Cortex prism_adapter wraps that output in Signal+Block+ViewHint.


8. Lens Editor — Tiers and Scope

Lens editing is a real product surface. Phased approach:

Tier Capability Effort
0 — Upload + Validate Drop a YAML in the lens registry; validator MCP tool returns parse errors; saved if valid. CLI + REST endpoint. small (~3 days)
1 — Form-based editor Auto-generate form from lens_spec.schema.json; pick lens type, set fields, sliders for thresholds, dropdown for transforms. Live validate. medium (1-2 weeks frontend + small Cortex MCP support)
2 — Visual flow editor Drag-and-drop blocks for layers, weights, threshold curves; render preview against test data. large (~1 month, requires real customer signal)
3 — LLM-assisted "Build me a lens that screens UK customers against VRS, prefer recall" → generates YAML + explains tradeoffs. research-grade

Tier 0 is the unblock. Required for any lens-as-config story. Tier 1 is the first customer-visible edit experience. Tiers 2-3 are roadmap.


9. Phased Sequencing

Phase Duration Deliverables Owner
1 — Define contracts (this doc) 1-2 days SPEC-33 v1 frozen; sub-tickets named CPO + me
2 — Cortex integration plumbing 1-2 sprints Lens runtime dispatcher; unified signal/block emitter with view_hint; lens registry; parallax adapter (Prism adapter scaffold) Cortex team
3 — Beacon dispatcher + missing components 1 sprint ViewHint dispatcher; gantt, choropleth, polyline_with_cost, uncertainty-ellipse components Beacon team (Jocelyn)
4 — Lens editor Tier 0 → Tier 1 1 sprint each Tier 0 (upload + validate); Tier 1 (form-based editor) Beacon + Cortex MCP support
5 — Prism adapter (when Prism is ready) 1-2 weeks Wire each Prism lens type's output → component name Prism team / future hire

Phase 1 unblocks Phase 2 and Phase 3 to run in parallel. Phase 4 can start once Phase 2's lens registry + validator MCP exist. Phase 5 is on Prism's timeline.


10. Open Questions

  1. Where does the lens registry physically live? UDS (cleanest — one ABAC story) or a separate UDS-adjacent store? Recommend UDS, treat lens YAMLs as a special object type.
  2. How do lens versions resolve at fusion time? Pin to version in the signal? Allow "latest" with audit-trail of which version ran? Recommend pin-by-default for replay-determinism (FED-SPEC-02).
  3. What's the ABAC story for lens editing? Who can save a new lens? Who can edit existing? Recommend: lens editing requires lens_authoring scope; lens execution requires fusion_operator scope. Lens YAMLs themselves are subject to ABAC like any other UDS object.
  4. How does this interact with SPEC-30 MachineDissent? Dissent records are themselves a signal type — signal_type: machine_dissent with the dissent payload as the block. Same pattern. Use case walk in §4 includes this row.
  5. Cueing orchestrator (epic #35) interaction. When a signal triggers downstream sensor tasking, what's the Cue payload schema? SPEC-32 (Wire Message Families) Operational family is the right bucket; SPEC-33 needs a small "outbound trigger" section in v2 of this doc once #35 has a Phase 1 design.

11. Sub-tickets to file (Cortex)

These become the implementation tickets under #229:

Title Phase Estimate
Cortex: Lens runtime dispatcher with engine adapter pattern 2 5d
Cortex: Lens registry MCP tools (save / get / list / freeze / version) 2 3d
Cortex: Lens validator MCP tool (returns structured errors) 2 2d
Cortex: Extend create_block / create_signal with view_hint field 2 1d
Cortex: Parallax adapter (entity_match → ViewHint(cluster_card)) 2 2d
Cortex: Prism adapter scaffold (4 lens types → 4 view_hints) 2 3d

12. Sub-tickets to file (Beacon)

Title Phase Estimate
Beacon: ViewHint dispatcher in signal-render path 3 2d
Beacon: gantt component 3 4d
Beacon: choropleth component 3 4d
Beacon: polyline_with_cost component 3 3d
Beacon: geo_overlay_with_uncertainty component 3 3d
Beacon: Lens editor Tier 0 (upload + validate) 4 5d
Beacon: Lens editor Tier 1 (form-based, schema-driven) 4 8d

13. Anti-goals (what this spec is NOT)

  • Not a re-architecture. Reuses the existing Block/Signal/ABAC/UDS infrastructure. Adds one new contract (ViewHint), extends two (Block, Signal).
  • Not a customer-facing doc. This is implementation-grade architecture. GTM language for "lens-as-config" / "lens editor" / "Decision Lens" lives in chris-gtm/.
  • Not Beacon-internal architecture. Beacon's NgRx + component patterns are out of scope. ViewHint dispatcher is one new piece in an existing component.
  • Not a replacement for SPEC-32. SPEC-32 defines wire-message families (Capability / Cue / Fusion / Evidence / Operational) that flow over RabbitMQ. SPEC-33 defines what ADI does WITH those messages once they arrive. Complementary specs.

14. Glossary

Term Meaning
Identity Lens Parallax — "are these records the same entity?"
Cost Lens / Decision Lens Prism — "what's the cost / risk / window / route?"
ADI Axonis Decision Intelligence platform (Beacon + Cortex + UDS)
Signal Header-level event in the Monitor queue
Evidence Block Full pedigree, frozen, signed
ViewHint Render directive carried by signal/block
Component Beacon UI widget
Lens registry UDS-backed store of validated lens YAMLs
MCP tool Cortex callable tool exposed via the MCP protocol

End of SPEC-33 Draft 1. To freeze for v1: review with Cortex lead + Beacon lead + Prism owner; resolve §10 open questions; assign Phase 2/3 tickets.


Depends on: component.parallax.dissent, component.parallax.wire-message-families

Realizes: product.fusion

Required by: component.parallax.coordination-ledger