Skip to content

Decision Effect

Definition

A Decision Effect is an automated downstream action the platform takes after a decision is sealed — i.e. after an Edition is attested. When a commander approves a containment order, the platform should not merely record the decision; it should act on it — create follow-up WorkflowTasks, notify external systems, or dispatch agents. The DecisionEffect object is the unit that captures that a sealed decision produced an outbound action and what happened to it, without prescribing how the action is transported.

Attestation is the firewall. Decision Effects belong to the execution layer (DES "Layer C"): they exist only because a human attested an Edition (Layer B), and they are derived from the effects[] configuration on that Edition's decision template. Without Decision Effects, attestation is a dead end — the human decides, but nothing happens automatically. Decision Effects are the first feature that consumes the attestation + provenance infrastructure to do something with a decision.

  • #REQ.triggered-by-attestation — A DecisionEffect is created when an Edition is attested, driven by the decision template's effects[] configuration. No attestation → no effect.
  • #REQ.records-not-transports — The DecisionEffect records that an outbound action was produced and what happened to it (status, acknowledgments, hashes). It does not define the transport: no endpoint URLs, webhook configs, retry policies, routing instructions, or agent communication protocols live on the object.

This spec describes the Effect as a domain object — its trigger, lifecycle, dispatch, and types. It is distinct from the WorkflowTask lifecycle: WorkflowTasks (product.task) are deliberation-phase work items that produce evidence and decisions; Decision Effects are post-attestation actions that execute sealed decisions. See §related for the boundary.

Lifecycle

status: pending → acknowledged → {completed | failed | timed_out}, with a cancelled exit before completion.

pending ──ack──▶ acknowledged ──complete──▶ completed
   │                  │
   │                  └──fail──▶ failed
   │
   └──timeout──▶ timed_out ──▶ Signal (escalation)
Status Meaning
pending Effect created, awaiting acknowledgment from the target
acknowledged Target confirmed receipt
completed Target confirmed successful execution
failed Target reported failure (with failure_reason)
timed_out deadline elapsed without completed/failed — generates an escalation Signal
cancelled Effect withdrawn before completion
  • #REQ.lifecycle-states — The Decision Effect lifecycle is pending → acknowledged → completed, with failed, timed_out, and cancelled as terminal exits. Transitions are validated, not orchestrated.
  • #REQ.transitions-logged — Every status transition is appended to the investigation's append-only event ledger as an effect event (see §journey). Status is descriptive and auditable, never silently mutated.

Trigger → Dispatch → Outcome

The Decision Effect moves through three phases:

  1. Trigger. An Edition is attested. Cortex reads the decision template's effects[], evaluates each entry's optional condition, and for each match creates a DecisionEffect doc (status: pending, created_by actor.type: system, correlation_id linking to the effect_created ledger event). The originating attested event is the provenance anchor.
  2. Dispatch. The EffectDispatcher persists the Decision Effect and hands it to the handler matching its effect_type. The first handler is agent_dispatch, which calls an external MCP endpoint (outbound MCP). Dispatch does not block Edition creation — Decision Effects are evaluated post-attestation and run asynchronously.
  3. Outcome. The target acknowledges, completes, or fails; or the deadline elapses and the effect times out. Each outcome is recorded on the object and emitted as a ledger event. A timed_out effect raises an escalation Signal that re-enters the OODA flow.

  4. #REQ.dispatch-nonblocking — Decision Effect evaluation and dispatch happen post-attestation and MUST NOT block or fail Edition creation. A failing Decision Effect is recorded as failed/timed_out, never rolled back onto the Edition.

Decision Effect types

effect_type Description Pack-config equivalents
external_dispatch Action sent to an external system (billing, logistics, CRM, regulatory, core banking). Dispatched via a handler such as agent_dispatch (outbound MCP). external_routing, webhook
notification Informational notice (email, webhook, message) to a recipient/subscriber — no completion expected. notification
human_process Action assigned to a person or team outside the decision system — bridges back to a new WorkflowTask (Layer A) via create_task(). task_creation
  • #REQ.effect-types — The Decision Effect type taxonomy is external_dispatch | notification | human_process. The pack-level config vocabulary (external_routing, webhook, notification, task_creation) maps onto these three DES types; the object stores the DES effect_type.
  • #REQ.agent-dispatch-handler — At least one handler (agent_dispatch) dispatches an external_dispatch effect to an external agent over MCP (outbound). Handlers are pluggable per effect_type; agent_dispatch is the first.
  • #REQ.notification-no-completion — A notification effect expects no completion acknowledgment; it reaches a terminal state on send and does not block on a target confirming execution.
  • #REQ.human-process-creates-task — A human_process Decision Effect (pack task_creation) creates a new WorkflowTask via create_task() with actor.type: system and origin_event_id pointing at the attested event. This is the one-way bridge from the execution layer back into the deliberation layer.

Journey through the code

The Decision Effect's path through cortex (cortex#279cortex#283):

  1. Persist (2.1, cortex#279). A DecisionEffect persistent object with Elasticsearch CRUD — id eff_ + suffix, stored alongside the other intelligence objects.
  2. State machine (2.2, cortex#280). The effect lifecycle state machine validates transitions per §lifecycle; illegal transitions are rejected.
  3. Ledger events (2.3, cortex#281). Each effect transition appends an event to the investigation's append-only event ledger (effect_created, and the per-transition follow-ons), so the effect's whole history is replayable from the ledger.
  4. Dispatcher wiring (2.4, cortex#282). The EffectDispatcher is wired to persist effects on creation and update them as outcomes arrive — the bridge between the decision template's effects[] and the stored object.
  5. Outbound handler (2.5, cortex#283). The agent_dispatch handler performs the first outbound MCP call to an external agent endpoint.

Decision Effects are surfaced in decision lineage: the get_decision_lineage tool/output includes the Decision Effects an attested Edition produced, so the decision and its downstream actions are inspectable together.

  • #REQ.lineage-visibility — Decision Effects produced by an attested Edition MUST be visible in get_decision_lineage output, alongside the Edition and its provenance.
  • #REQ.es-persistence — DecisionEffect is a persistent object with Elasticsearch CRUD, identified by an eff_ id; it is not ephemeral dispatch state.

Data shape

Required: schema_version, effect_id (eff_ prefix), edition_id (the attested Edition that produced it), insight_id (the investigation that produced the Edition), effect_type (see §types), target (implementation-defined target system/process), payload_hash (SHA-256 of the effect payload at creation), status (see §lifecycle), created_at, created_by.

Optional: action (human-readable label), payload_summary, deadline (ISO 8601), correlation_id (event id linking to the effect_created ledger entry), completed_at, failure_reason (when failed), external_reference (id returned by the external system).

  • #REQ.payload-hashpayload_hash is computed from the effect payload at creation time. If the action is later disputed, the hash proves what was sent.

Invariants

  • #REQ.requires-attested-edition — A Decision Effect MUST reference an attested Edition via edition_id. Unattested decisions cannot generate Decision Effects — the Edition (Layer B) is the firewall between deliberation and execution.
  • #REQ.one-way-firewall — Decision Effects flow one way: Decision Effects can create WorkflowTasks (human_processcreate_task()); WorkflowTasks cannot create Decision Effects. Nothing crosses from the deliberation layer to the execution layer except through an attested Edition.
  • #REQ.timeout-raises-signal — When a Decision Effect's deadline passes without completed or failed, the system records an effect_timeout event and generates a signal_type: effect_timeout, severity: high Signal. That Signal enters the standard OODA flow as a decision_driven investigation referencing the original Edition; the chain is traceable via correlation_id. This is the self-healing escalation loop for stuck effects.
  • #REQ.append-only-ledger — Effect events are append-only on the investigation ledger; the object's status is descriptive of (not a substitute for) that audit trail.

Done-when

The behavior EPIC #12 (Decision Effects System, Connor Epoch 2) delivers is complete when:

  • #REQ.done-effects-on-attest — Attesting an Edition whose decision template carries effects[] creates DecisionEffect docs in Elasticsearch.
  • #REQ.done-validated-and-logged — Effect status transitions are validated and logged as ledger events.
  • #REQ.done-one-handler — At least one handler (agent_dispatch) successfully calls an external MCP endpoint.
  • #REQ.done-lineage — Effects are visible in get_decision_lineage output.

Prerequisite infrastructure (Connor epochs): Epoch 0 MCP subscribe and Epoch 1 MCP agent + block provenance metadata must be in place — effects are the first feature that uses that infrastructure to act after a decision.

  • product.task — the deliberation-phase counterpart. A WorkflowTask produces evidence and decisions (Layer A); a Decision Effect executes a sealed decision (Layer C). They are distinct objects with distinct lifecycles. The only link is the one-way human_process bridge: a Decision Effect MAY create a WorkflowTask; a WorkflowTask never creates a Decision Effect.
  • component.cortex.task-and-effect — cortex's component contract for both objects. It owns the WorkflowTask lifecycle and carries the pack-level Decision Effect declaration syntax and dispatch implementation guidance (#effect, #effect.declaration, #effect.mapping, #effect.one-way). The authoritative Decision Effect schema it points at is component.cortex.decision-evidence#effect.
  • product.edition — the attested Edition is the trigger and the firewall; a Decision Effect references it via edition_id and cannot exist without it.
  • component.sentinel.alerting — the notification/escalation surface. Effect timeouts raise Signals that feed decision-intelligence alerting; sentinel is a co-owner of the notification side of effect outcomes.

Open questions

  • Handler registry. agent_dispatch is the first handler; the registration mechanism for additional external_dispatch/notification handlers (and whether handlers are pack-declared or code-registered) is not yet specified.
  • Federated verification. When both originating and target systems are DES-compliant, an acknowledgment MAY carry cross-system hash references (external_reference, external_ledger_ref, completion_hash) pointing at the target's own sealed Edition. The federation protocol for this is informative only and not yet pinned.
  • cancelled trigger. The lifecycle admits cancelled before completion, but who may cancel an in-flight effect, and under what authorization, is unspecified.

Required by: platform.relay

Realized by: component.conduit.effect-engine