Consensus Mission Service
Status & scope
- Stage: DRAFT — service layer (implementation target: REST per CL-06, NOT the parallax library)
- Depends on: multi-contributor-combination (combiner), consensus-session, dissent, CL-06 (REST-only), CL-09 (evidence chain), CL-10 (multi-tenant)
- Milestone: P1 — gates Q3 2026 GA; required for defense / coalition deployments
Purpose
SPEC-28 / SPEC-36 / SPEC-30 define combiner math, session state machine, and machine dissent. They need a home — a named service that consumes contributions, drives the state machine, calls the combiner, emits dissent, and manages cross-tenant federation handoff.
This spec names that service: Consensus Mission Service. It is the JICD §4.4.5 Mission Service Node Axonis registers with a CS Hub when peering with a JICD deployment, and it is the REST-callable consensus surface in any non-JICD deployment.
The service is REST-only (per CL-01: no MCP outside Profile A). It implements the consensus session endpoints from CL-06 and is the reference implementation of the SPEC-36 state machine.
Relationship to SPEC-PLATFORM-04
This service is net-new relative to the six services enumerated in SPEC-PLATFORM-04 (Parallax, Prism, Cortex, Unified Dataspace, Oracle, Sentinel). It is NOT a subset of Parallax or Prism, despite consuming their outputs.
Rationale for separate service rather than Parallax extension:
- Parallax's domain (per PLATFORM-04) is fusion entity resolution — two-record pair scoring, blocking, clustering. The 19 listed Parallax tools are CRUD + workflow + introspection over
Lens,LensBinding,EntityMatch,EntityCluster,FusionRun. Adding session-shaped multi-contributor consensus to that surface conflates pair-level fusion with N-party combination. - Consensus has its own object model (
ConsensusSession,MachineDissent) and its own ES index — clean separation from Parallax'sfusionindex. - Profile-aware deployment: Consensus Mission Service runs in T1/T2/T4/T5 (where N-party combination happens); does NOT run in T3 Lookup-Light Edge Nodes (where there's only one matching node and no N-party combination). Parallax has different profile semantics.
- JICD §4.4.5 Mission Service registration is a distinct Capability advertisement — separate component is the cleaner JICD composition.
Action required: SPEC-PLATFORM-04 amend to add this service as Service 7 alongside Sentinel:
Service 7: Consensus Mission Service Port 8400. /api/v2. Domain: multi-contributor consensus combiner, M-of-N quorum, machine dissent. See SPEC-31 for full specification.
Until that amendment lands, Consensus Mission Service operates as a peer-named service following SPEC-PLATFORM-02's contract — same Helm/CI/auth/health pattern as the six existing services, just not yet listed in PLATFORM-04's enumeration.
Scope
The Consensus Mission Service is responsible for:
- Hosting the consensus session lifecycle (PROPOSED → PENDING_QUORUM → RATIFIED | IN_CONFLICT | WITHDRAWN)
- Invoking the SPEC-28 combiner on every contribution
- Emitting MachineDissent records (SPEC-30) on IN_CONFLICT entry
- Emitting Evidence Blocks (CL-09) on RATIFIED entry
- Emitting lens emissions (CL-06) downstream when ratified results should propagate to consumers
- Federation handoff — accepting cross-deployment contributions per CL-07 transport adapters
- Tenant-scoping all sessions per CL-10
- Surfacing observability (metrics, audit views) via REST
It is NOT responsible for:
- Pair-level scoring (Parallax service does this)
- Lens execution (Parallax / Prism services do this)
- Vulnerability code lookup or domain-specific result enrichment (cartridge / customer adapter handles this)
- Human attestation UX (ADI/DES handles this)
- Anything that runs in Profile B Edge Nodes (the Lookup-Light pattern doesn't use this service)
Service Anatomy (per SPEC-PLATFORM-02 contract)
consensus-service/
server/
__init__.py
__main__.py # Starlette: /api/v2, /health, /service-info
api/
__init__.py
routes.py # FastAPI REST endpoints
schema/
consensus_objects.yml # OpenAPI component schemas
commands.py # Command layer (REST + MCP if Profile A)
mcp/ # Profile A only (per CL-01); skipped otherwise
server.py
tools.py # Mirror of REST surface as MCP tools
charts/consensus-service/
pyproject.toml # Depends on axonis-core, parallax (for combiner)
Profile-aware: in Profile A, the MCP surface is mounted at /agentspace. In Profiles B/C/D, only /api/v2 is exposed.
REST Surface (matches CL-06)
| Method | Path | Purpose |
|---|---|---|
| POST | /api/v2/consensus/session |
Create session |
| GET | /api/v2/consensus/session/{id} |
Get session state |
| POST | /api/v2/consensus/session/{id}/contribution |
Add contribution |
| POST | /api/v2/consensus/session/{id}/resolve |
Force resolve attempt |
| POST | /api/v2/consensus/session/{id}/cancel |
Cancel session → WITHDRAWN |
| GET | /api/v2/consensus/session/{id}/events |
SSE stream (optional) |
| GET | /api/v2/dissent |
List dissent records |
| GET | /api/v2/dissent/{id} |
Get specific dissent |
| GET | /api/v2/dissent/by-session/{session_id} |
All dissent for a session |
| GET | /api/v2/dissent/{id}/explain |
Human-readable narrative |
| POST | /api/v2/federation/contribution |
Accept contribution from a federation peer (signed, per CL-07) |
| GET | /api/v2/health |
Liveness |
| GET | /api/v2/service-info |
Service metadata per SPEC-PLATFORM-02 |
Command Layer
The command layer is the canonical implementation of the SPEC-36 state machine and is shared by REST endpoints (and by MCP tools in Profile A).
# consensus-service/server/commands.py
from parallax.ops.consensus_session import (
create_session as _create, add_contribution as _add,
SessionState, QuorumPolicy,
)
from parallax.ops.dissent import emit_machine_dissent
from parallax.ops.fusion.combination import Contribution
from axonis_core.userspace.fusion import ConsensusSession, MachineDissent
from axonis_core.gateway.transport import get_transport
def create_session_cmd(lens_id, lens_version, policy_dict, classification, token_payload):
policy = QuorumPolicy(**policy_dict)
return _create(
lens_id=lens_id,
lens_version=lens_version,
policy=policy,
tenant_id=token_payload.tenant_id,
classification=classification,
)
def add_contribution_cmd(session_id, contribution_dict, token_payload):
# Tenant boundary check (CL-10)
session = ConsensusSession().read(uid=session_id)
if session["tenant_id"] != token_payload.tenant_id:
raise PermissionError("session belongs to different tenant")
contrib = Contribution(**contribution_dict)
return _add(session_id, contrib)
def federation_contribution_cmd(payload, transport_message):
"""Called when a federation peer pushes a contribution via CL-07 transport.
The transport adapter validates the signature; this command verifies tenant
routing and delegates to the same _add() the local REST path uses."""
# Verify cross-tenant routing per CL-10 federation-as-tenant
sender_tenant = transport_message.sender_tenant_id
target_tenant = transport_message.receiver_tenant_id
session_id = payload["session_id"]
session = ConsensusSession().read(uid=session_id)
if session["tenant_id"] != target_tenant:
raise PermissionError("federation contribution targets wrong tenant")
# Federate-as-tenant: the sending peer is a contributor identified by sender_tenant
contrib = Contribution(
contributor_id=sender_tenant,
pair_score=payload["pair_score"],
accuracy=payload["accuracy"],
credibility=payload["credibility"],
signer_key_id=transport_message.signer_key_id,
classification=payload["classification"],
)
return _add(session_id, contrib)
REST endpoints in api/routes.py are thin wrappers that authenticate via CL-02 provider, delegate to commands, return JSON.
Federation Handoff (CL-07)
When a deployment runs the Consensus Mission Service and federates with peers (other Axonis deployments, JICD CS hubs, partner systems), contributions can arrive two ways:
Local contribution
A local service (Parallax pair-scorer, Prism lens executor, Edge Node submission) calls POST /api/v2/consensus/session/{id}/contribution directly. Authenticates via the local CL-02 provider.
Federation contribution
A peer pushes a contribution via the configured CL-07 transport (mTLS, SILKWAVE, AMQP, file-drop CDS). The transport adapter:
1. Validates the message signature against the peer's pinned key
2. Validates classification per CL-08 routing rules
3. Hands off to federation_contribution_cmd() which adds to the session
Federate-as-tenant (CL-10) means the sending peer's sender_tenant_id becomes the contributor_id in the session. Per-federate lineage is preserved via the signer_key_id and the parent block IDs.
JICD CS Composition
When deployed alongside JICD CS:
- The Consensus Mission Service registers with the local CS Hub as a Mission Service Node (JICD §4.4.5)
- Capability message declares: "I host consensus sessions; I accept contributions of type X over lens Y"
- Other CS Nodes (Processor Nodes running lens execution, Tasker Nodes coordinating mission) discover the service via standard JICD RCS
- Contributions arrive via SILKWAVE-transported FusionMessages (CL-07 SilkwaveAdapter); the same
federation_contribution_cmdpath handles them
This is how Axonis composes into JICD as a Mission Service. The Capability message Mike's team sees in their JICD dashboard names this service explicitly, and any Tasker Node can subscribe to its Status feed for ratification events.
Service-Info Response
{
"name": "consensus-service",
"version": "1.0.0",
"description": "Multi-contributor consensus combiner + quorum + machine dissent",
"mcp_path": "/agentspace",
"health_path": "/health",
"api_path": "/api/v2",
"tools_count": 0,
"resources_count": 0,
"capabilities": [
"consensus-session",
"machine-dissent",
"federation-contribution",
"spec-28-combiner",
"spec-29-quorum",
"spec-30-dissent"
],
"deployment_profile": "<from CL-01>",
"supported_combination_methods": ["weighted_average", "dempster_shafer"],
"supported_transports": ["<from CL-07 configuration>"]
}
In Profile A, tools_count reflects MCP tools mirroring the REST surface. In Profiles B/C/D, tools_count: 0 and mcp_path is omitted.
Observability
| Endpoint | Purpose |
|---|---|
GET /api/v2/metrics |
Prometheus-formatted: session counts by state, dissent emissions, combiner latencies, federation contribution rates |
GET /api/v2/health |
Liveness + dependency check (ES, transport adapter) |
GET /api/v2/audit |
Recent session lifecycle events for human / SIEM consumption |
Metrics taxonomy:
- consensus_session_total{state} — counter
- consensus_session_active{state} — gauge
- consensus_combiner_seconds{method} — histogram
- consensus_dissent_total{lens_id} — counter
- federation_contribution_total{transport, peer} — counter
In Profile C/D, metrics endpoints stay inside the deployment boundary per CL-01 invariant 6.
Helm + CI (per SPEC-PLATFORM-02)
Standard Bitnami chart at charts/consensus-service/:
- Port 8400 (next available in the platform's port assignments)
- Resources: 500m–2 CPU, 1–4 GB RAM (combiner is mostly arithmetic; ES queries dominate)
- HPA on request rate
- ServiceAccount + ClusterRoleBinding for ES access
CI pipeline matches the standard template: qa, package, deploy, release, security.
Invariants
- Service is REST-first. All business logic reachable via REST in every profile.
- Profile-aware MCP. MCP surface mounts only in Profile A; non-existent in Profiles B/C/D.
- All sessions are tenant-scoped. Cross-tenant operations route through federation, never direct.
- State machine logic lives in
parallax/ops/consensus_session.py(per SPEC-36). This service is a thin REST layer over that logic. - Combiner logic lives in
parallax/ops/fusion/combination.py(per the multi-contributor-combination spec). This service does not duplicate. - Federation contributions verify signatures before mutation. No unsigned cross-deployment contribution is accepted.
- Service registers with JICD CS Hub when configured to compose (JICD-deployed sites only). Capability + Status messages match JICD §4.4.5 specification.
- No agentic behavior. This service does not autonomously decide to call tools or make decisions. It executes the state machine on inputs and emits results.
Deployment Topologies
| Topology (CL-03) | Where this service runs |
|---|---|
| T1 single cluster (Profile A) | Yes, alongside other services; MCP active |
| T2 multi-tenant cloud (Profile A) | Yes, single instance with tenant-scoped sessions |
| T3 customer on-prem (Profile B) | Optional — needed only if customer hosts a federated multi-INT use case (rare for VRS-style deployments) |
| T4 coalition federated (Profile C) | Yes, one per partner; peers contribute via CL-07 transport |
| T5 classified air-gapped (Profile D) | Yes; federation via accredited cross-domain interfaces only |
For Lookup-Light Edge Node deployments (VRS / commercial centralized matching), this service runs at the central matching node, not at the customer edge. Customer Edge Nodes don't host consensus sessions because there's no N-party combination on the customer side.
Test Expectations
- Service-contract conformance:
/health,/service-info,/api/v2/*all responsive; auth via CL-02 provider; profile-aware MCP mount. - Local + federation contribution parity: same lens, same contributions; one session sees both arrive locally and ratifies; another sees one arrive locally, one via federation; results match.
- Tenant isolation: session for tenant A cannot accept contribution authenticated as tenant B.
- JICD registration test: start service with JICD CS Hub URL configured; verify Capability and Status messages appear on the hub.
- State machine integration test: create session → 3 contributions over time → SSE stream shows PROPOSED → PENDING_QUORUM → RATIFIED with combiner result.
- Conflict path test: contributions trigger IN_CONFLICT → MachineDissent record appears → human attestation resolves → audit chain shows full lineage.
- Federation transport test: swap transport adapters (mTLS / AMQP / SILKWAVE); behavior identical at the application layer.
- Profile B refusal test: start service with
AXONIS_DEPLOYMENT_PROFILE=customer_onpremand Lookup-Light cartridge declared; service refuses to start with clear error (consensus service requires Full Lens profile).
Cross-Reference
- SPEC-28: combiner math invoked here
- SPEC-36: state machine implemented here
- SPEC-30: dissent emission triggered here
- CL-01: deployment profile gates MCP availability
- CL-02: pluggable auth on every endpoint
- CL-03: topology determines where this service runs
- CL-06: REST-only consensus session primitive
- CL-07: federation transport adapter feeds contributions in
- CL-08: classification routing
- CL-09: evidence Blocks emitted on RATIFIED
- CL-10: tenant scoping on every operation
Depends on: component.parallax.consensus-session, component.parallax.dissent, component.parallax.multi-contributor-combination
Realizes: product.fusion