Cortex — Decision Evidence Specification (DES) Core
DES defines a minimal schema for capturing the evidence behind high-stakes decisions: the full lifecycle from signal to sealed, auditable decision artifact. It standardizes the artifact layer of decisions — schemas, lifecycle semantics, integrity contracts — not the runtime, UI, storage engine, or execution layer.
This spec is the schema authority for the five DES core objects (Signal, Investigation, Block, Event, Edition) plus the optional Decision Effect extension. The lifecycle specs (component.cortex.signal-lifecycle, component.cortex.investigation-lifecycle, component.cortex.task-and-effect) add runtime behavior on top of these schemas. The Fields Reference tables here are canonical: do not invent field names, enum values, or event types not listed.
Problem Statement
High-stakes decisions happen every day in banking, healthcare, emergency management, regulatory compliance, and government. The decision itself is often recorded; the evidence behind it is not. Current systems capture what was decided — not why, not what evidence was considered, not who was accountable, and critically not why nothing happened when a decision was deliberately not made. DES defines a portable, verifiable evidence chain from signal to decision.
Object Model
DES defines five core objects and one optional extension. Each has a named identifier, a schema version, and well-defined relationships.
Signal ──triggers──▶ Investigation ──gathers──▶ Blocks
│ │
│ pin + freeze
│ │
└──produces──▶ Edition ◀─┘
│
attest
│
Sealed Record
│
(optional) effect
│
Decision Effect ──timeout──▶ Signal (escalation)
Five core objects: Signal, Investigation (wire: insight), Block, Event, Edition. One optional extension: Decision Effect (§effect), which tracks execution of sealed decisions into external systems. Effects are not part of the deliberation layer — they are an informative extension adopted when execution auditability is required.
Identifier Format
All DES objects use human-readable, prefixed identifiers generated from UUIDv4 hex, truncated to 12 characters. Implementations MAY use longer identifiers but MUST preserve the prefix convention.
| Object | Prefix | Format | Example |
|---|---|---|---|
| Block | blk_ |
blk_{12 hex chars} |
blk_a1b2c3d4e5f6 |
| Investigation | ins_ |
ins_{12 hex chars} |
ins_9f8e7d6c5b4a |
| Event | evt_ |
evt_{12 hex chars} |
evt_f0e1d2c3b4a5 |
| Edition | edn_ |
edn_{12 hex chars} |
edn_x1y2z3w4v5u6 |
| Effect | eff_ |
eff_{12 hex chars} |
eff_m1n2o3p4q5r6 |
INVARIANT: Every object carries a create_ts (ISO 8601). It is immutable once set.
Evidence Block
The fundamental unit of evidence. A Block wraps any piece of data, analysis, note, or artifact that contributes to a decision.
Block Kinds
| Kind | Description |
|---|---|
query_result |
Data retrieved from a source system |
ai_summary |
Machine-generated analysis with citations |
manual_note |
Human-authored observation |
external_reference |
Link to external document, filing, or artifact |
artifact_evidence |
Computed output: KPI, model prediction, schema card |
Outcome
The outcome records what the query returned, not what was expected.
| Outcome | Meaning |
|---|---|
OK |
Evidence retrieved successfully |
NO_DATA |
Query executed, no matching data found |
PARTIAL |
Some sources returned data, others did not (e.g., visibility boundary) |
ERROR |
Query failed |
Access control filtering is transparent. If a governance layer omits fields or records based on the requester's authorization, the block records PARTIAL or NO_DATA — never the reason for omission. Evidence artifacts must not leak access policy details.
Evidence Lifecycle
Every block progresses through a strict, forward-only lifecycle:
TRANSIENT ──pin──▶ CURATED ──freeze──▶ FROZEN
| Stage | Meaning | Mutable? | Hash Required? |
|---|---|---|---|
transient |
Working evidence. May be discarded. | Yes | No |
curated |
Pinned to an investigation with rationale. | Yes | No |
frozen |
Locked for a decision. Immutable. | No | Yes |
INVARIANT: Lifecycle transitions are forward-only. A frozen block cannot be unpinned or reverted to transient. A curated block cannot be reverted to transient.
Materialization Mode
| Mode | Meaning |
|---|---|
live |
Evidence can be re-queried. Content may differ on re-execution. |
frozen |
Evidence is a point-in-time snapshot. Content is immutable. |
INVARIANT: A block with materialization_mode: frozen MUST have a result_hash and a captured_at timestamp. Once set, the content covered by the hash can NEVER change.
Pinning
Pinning is a deliberate human action that advances a block from transient to curated and associates it with an investigation. It requires a pin_rationale — a human-readable explanation of why this evidence is relevant.
INVARIANT: A frozen block MUST NOT be pinned. Pinning is an editorial action; frozen evidence is already committed.
Block State Machine
States: { TRANSIENT, CURATED, FROZEN } Initial: TRANSIENT Terminal: FROZEN
| From | To | Trigger | Preconditions | Postconditions |
|---|---|---|---|---|
| TRANSIENT | CURATED | pin |
pin_rationale non-empty. insight_id set. |
lifecycle_stage = curated. Durable. |
| CURATED | FROZEN | freeze |
result_hash computed. captured_at set. |
lifecycle_stage = frozen. materialization_mode = frozen. Immutable. |
| TRANSIENT | FROZEN | freeze |
result_hash computed. captured_at set. |
Direct freeze (skips curated). |
Illegal: FROZEN→CURATED, FROZEN→TRANSIENT, CURATED→TRANSIENT. Once FROZEN, the block MUST NOT be modified, unpinned, or deleted.
Block Fields Reference
| Field | Required | Description |
|---|---|---|
schema_version |
Yes | Schema version (integer) |
block_id |
Yes | Unique identifier (blk_ prefix) |
block_kind |
Yes | Evidence type (see §block.kinds) |
create_ts |
Yes | ISO 8601 creation timestamp. Immutable once set. |
title |
No | Human-readable title |
lifecycle_stage |
No | Current lifecycle position (default transient) |
materialization_mode |
No | live or frozen (default live) |
outcome |
No | Query result status (see §block.outcome) |
origin_surface |
No | Where the block was created (e.g. dashboard, investigation, review) |
query_fingerprint |
No | Technology-agnostic representation of the query |
data_sources |
No | Array of data source identifiers |
content |
No | Free-form JSON content (for summaries, notes, references) |
result_hash |
Frozen | SHA-256 hash of content (required when frozen) |
query_hash |
No | Hash of query parameters for deduplication |
captured_at |
Frozen | ISO 8601 timestamp (required when frozen) |
insight_id |
No | Investigation this block belongs to |
pin_rationale |
Curated | Why this evidence was pinned (required when curated) |
evidence_class |
No | Domain-specific routing label |
evidence_tags |
No | Array of freeform tags |
viz_hints |
No | Visualization recommendations (see component.cortex.data-shape) |
column_meta |
No | Column metadata for tabular evidence |
rehydration |
No | Parameters for re-executing a live block |
warnings |
No | Execution warnings |
errors |
No | Execution errors |
Signal
A Signal is an external trigger that may warrant investigation — an alert, threshold breach, anomaly, or manual flag. See component.cortex.signal-lifecycle for transition rules, policy mechanics, and disposition semantics.
Signal Severity
| Severity | Description |
|---|---|
critical |
Requires immediate attention |
high |
Requires prompt attention |
medium |
Standard priority |
low |
Low priority, informational with action potential |
info |
Purely informational, no action expected |
Signal Source Types
| Source Type | Description |
|---|---|
webhook |
External system push notification |
mcp |
Generated via MCP tool call |
polling |
Detected by periodic polling |
internal |
Generated by internal computation (cross-signal correlation, SLA breach) |
manual |
Manually created by a user |
computed |
Derived from signal policy evaluation |
Signal Fields Reference
| Field | Type | Required | Description |
|---|---|---|---|
signal_id |
string | Yes | Prefixed identifier (sig_{12 hex}) |
schema_version |
integer | Yes | Schema version (currently 2) |
signal_type |
string | Yes | Domain-specific type (e.g. utilization_spike); matches a signal policy policy_id for computed signals |
source.type |
string | Yes | Origin type (see §signal.sources) |
source.system_id |
string | Yes | Identifier of the originating system |
source.system_name |
string | Yes | Human-readable system name |
severity |
enum | Yes | Signal severity (see §signal.severity) |
subject.type |
string | Yes | Entity type (e.g. customer, account) |
subject.id |
string | Yes | Entity identifier |
subject.name |
string | Yes | Entity display name (use subject.name, not display_name) |
title |
string | Yes | Human-readable signal title |
description |
string | Yes | Detailed description of what was detected |
detected_at |
ISO 8601 | Yes | When the signal was detected |
expires_at |
ISO 8601 | No | When the signal expires (if applicable) |
status |
enum | Yes | Current state (see component.cortex.signal-lifecycle) |
confidence |
float | No | Detection confidence (0.0–1.0) |
metadata |
object | No | Domain-specific metadata (additionalProperties: true) |
related_signals |
array | No | IDs of related signals |
visibility_context |
object | No | Access control context (org_id, federates) |
routing |
object | No | Auto-routing rules (auto_acknowledge, assigned_to) |
payload |
object | No | Producer-specific payload; payload.assessment is the canonical scored-evidence shape (see §signal.assessment) |
Cortex stores additional fields under metadata via additionalProperties: true: created_by, status_history[] (array of {from, to, by, at, rationale}), resolved_by_edition, resolved_by_insight, and ad-hoc geolocation (lat, lon, location_wkt).
Signal Assessment (payload.assessment)
Scored producers (source.type = computed, e.g. a Prism lens) may attach payload.assessment, a contracted shape for ensemble/multi-layer evidence that free-form metadata cannot preserve:
| Field | Type | Description |
|---|---|---|
ensemble_score |
float | Aggregate confidence (0.0–1.0) |
ensemble_method |
string | Aggregation method (weighted_mean, max, vote, …) |
lens_id |
string | Producing lens id |
lens_version |
string | Lens version frozen at emission (replayability) |
threshold_crossed |
enum | confirm \| candidate \| reject — coarse band; evidence input only, never an automated decision |
layers[] |
array | Per-domain scored layers (below) |
Each layers[] entry: {domain, score, weight, origin, contributor_node, evidence_block_id, layer_spec_id}.
INVARIANT: evidence_block_id references a Block by UID — evidence is referenced, never embedded (DES Invariant 3).
INVARIANT: threshold_crossed is evidence presented to a human; it never triggers an automated decision (AI assists, humans attest). The emission funnel validates the band enum, the score bounds, and the evidence-by-reference rule.
Investigation
An Investigation (wire: insight) is an evidence-gathering session anchored to a subject. It tracks what evidence was collected, what events occurred, and what decisions resulted. See component.cortex.investigation-lifecycle for status semantics, transition rules, and session management.
Entry Modes
| Mode | Description |
|---|---|
signal_driven |
Triggered by a signal (alert, threshold breach, flag) |
curiosity_driven |
Analyst-initiated exploration |
task_driven |
Initiated from an assigned task |
decision_driven |
Review of a prior decision |
Investigation Status
| Status | Description |
|---|---|
draft |
Investigation in progress, evidence being gathered |
in_review |
Evidence gathering complete, under review |
approved |
Investigation approved |
published |
Investigation published and visible |
archived |
Investigation archived |
Investigation Fields Reference
| Field | Required | Description |
|---|---|---|
schema_version |
Yes | Schema version (integer) |
insight_id |
Yes | Unique identifier (ins_ prefix) |
title |
Yes | Human-readable investigation title |
create_ts |
Yes | ISO 8601 creation timestamp. Immutable once set. |
status |
Yes | draft, in_review, approved, published, archived |
entry_context |
Yes | Entry mode, trigger, subject reference, purpose |
heads |
Yes | Branch name → event_id mapping (DAG heads) |
created_by |
Yes | Actor who created the investigation |
pinned_block_ids |
No | Array of curated/frozen block IDs |
edition_ids |
No | Array of edition IDs produced from this investigation |
linked_signal_ids |
No | Array of signal IDs that triggered this investigation |
visibility_context |
No | Access control context (org_id, federates, deny_mode) |
subject |
No | Subject reference shorthand (type, id, display_name) |
rationales |
No | Stored rationale text (Cortex addition) |
narrative |
No | In-progress narrative sections (executive_summary, methodology, etc.) |
ai_usage |
No | Token and tool-call counters for AI-assisted investigations |
Entry Context Sub-fields
| Field | Required | Description |
|---|---|---|
entry_context.mode |
Yes | Entry mode (see §investigation.entry-modes) |
entry_context.trigger.type |
Yes | signal, task, decision, home, direct, api, scheduled |
entry_context.trigger.id |
No | ID of the triggering object (required for signal/task/decision) |
entry_context.subject_ref.type |
Yes | Entity type (e.g. customer, account) |
entry_context.subject_ref.id |
Yes | Entity identifier |
entry_context.subject_ref.display_name |
No | Human-readable name |
entry_context.purpose.purpose_type |
Yes | investigate, review, research, hunch, followup |
entry_context.purpose.decision_prompt |
No | What question this investigation seeks to answer |
entry_context.purpose.urgency |
No | routine, elevated, urgent |
entry_context.task_ref |
No | Originating task ID (required when mode = task_driven) |
entry_context.decision_ref |
No | Prior decision ID (required when mode = decision_driven) |
INVARIANT: Every investigation MUST have a subject_ref with type and id. An investigation must be about something.
Event Ledger
Every action during an investigation is recorded as an immutable event. Events form a directed acyclic graph (DAG) via parent_event_id, with branch heads tracked in the investigation's heads field. The main branch head always points to the latest event (analogous to git log --first-parent).
INVARIANT: Events are append-only. No UPDATE, no DELETE. The event ledger is the complete audit trail.
Most events are investigation-scoped (carry insight_id, participate in the DAG/branch structure above). Signal-scoped events (signal_created, signal_status_changed) are a distinct class on the same append-only ledger: they carry no insight_id, no parent_event_id, and no branch — they are anchored by payload.signal_id. The append-only invariant applies identically; only the DAG/branch machinery is investigation-specific. (Signal-scoped events are written through cortex.signals.ingest; see component.cortex.signal-lifecycle#persistence.)
Core Event Types
| Event Type | When It Occurs |
|---|---|
signal_created |
Signal emitted onto the ledger (signal-scoped; payload carries the full document) |
signal_status_changed |
Signal lifecycle transition recorded ({signal_id, from, to}; signal-scoped) |
entry_intent_set |
Investigation created |
signal_linked |
Signal associated with investigation |
signal_disposition_set |
Signal classified or routed (on the linked investigation's ledger) |
block_created |
Evidence block captured (auto-journaled) |
block_pinned |
Block pinned to investigation with rationale |
block_unpinned |
Block removed from curated set |
block_frozen |
Block frozen for decision |
text_updated |
Narrative or summary text updated |
rationale_added |
Decision rationale recorded |
comment_added |
Comment on a block |
edition_created |
Edition snapshot created |
revision_committed |
Edition frozen with content hash |
review_requested |
Edition sent for review |
review_closed |
Review completed |
attested |
Edition attested by authorized party |
decision_tagged |
Tag applied to decision |
task_created |
Task spawned from investigation |
task_completed |
Task completed |
handoff_requested |
Investigation handed to another party |
Task extension event types (task_accepted, task_rejected, task_expired) are defined in component.cortex.task-and-effect#task.events.
Effect Event Types
Optional extension (see §effect):
| Event Type | When It Occurs |
|---|---|
effect_created |
Decision effect dispatched to external system |
effect_acknowledged |
External system confirmed receipt |
effect_completed |
External system confirmed execution |
effect_failed |
External system reported failure |
effect_timeout |
Deadline elapsed without acknowledgment or completion |
Event Legality by Actor Type
Not all events can be performed by all actor types. An implementation MUST reject events that violate this matrix.
| Event Type | user |
agent |
system |
|---|---|---|---|
signal_created |
YES | YES | YES |
signal_status_changed |
YES | NO | YES |
entry_intent_set |
YES | YES | YES |
signal_linked |
YES | YES | YES |
signal_disposition_set |
YES | NO | NO |
block_created |
YES | YES | YES |
block_pinned |
YES | NO | NO |
block_unpinned |
YES | NO | NO |
block_frozen |
YES | YES | YES |
text_updated |
YES | YES | NO |
rationale_added |
YES | NO | NO |
comment_added |
YES | YES | NO |
edition_created |
YES | NO | NO |
revision_committed |
YES | NO | NO |
review_requested |
YES | NO | YES |
review_closed |
YES | NO | NO |
attested |
YES | NO | NO |
decision_tagged |
YES | NO | NO |
task_created |
YES | NO | YES |
task_completed |
YES | NO | YES |
handoff_requested |
YES | NO | YES |
INVARIANT: attested events MUST have actor.type = user. This is the fundamental DES guarantee: AI assists, humans attest.
INVARIANT: When actor.type = agent, on_behalf_of MUST reference the human principal who authorized the agent's actions.
signal_created is YES/YES/YES — users (manual), agents (on behalf of a principal), and systems (computed-policy producers, timeout escalation) all legitimately create signals. signal_status_changed is YES/NO/YES — human transitions (acknowledge/disposition) and system auto-transitions (attest auto-resolve, expiry auto-dismiss, effect-timeout) are legal; agents do not set signal status directly (mirroring signal_disposition_set = user-only for the human-decides edges).
Event Fields Reference
| Field | Required | Description |
|---|---|---|
schema_version |
Yes | Schema version (integer) |
event_id |
Yes | Unique identifier (evt_ prefix) |
insight_id |
Conditional | Parent investigation. Required for investigation-scoped events; omitted for signal-scoped events (signal_created, signal_status_changed), which are anchored by payload.signal_id. |
create_ts |
Yes | ISO 8601 timestamp. Immutable once set. |
event_type |
Yes | Event type (see §event.core-types, §event.effect-types) |
actor |
Yes | Who performed the action |
parent_event_id |
No | Parent event for DAG structure |
branch |
No | Branch name (default main) |
payload |
No | Event-type-specific data (free-form object) |
usage |
No | LLM usage stats (model, input_tokens, output_tokens, tool_calls) |
actor.id |
Yes | Actor identifier (user email, agent ID, or system name) |
actor.type |
Yes | user, agent, or system |
actor.name |
Yes | Human-readable display name |
actor.on_behalf_of |
Agent | Human principal the agent acts for (required when type = agent) |
Evidence Manifest
An Evidence Manifest is an ordered list of frozen blocks that constitute the evidentiary basis for a decision. Each entry carries the block's identity and integrity digest: {block_id, title, digest, mode: frozen}.
The digest is computed from the block's structural content, not the raw storage representation, so different storage backends produce identical digests for the same evidence. Digest computation covers: block_kind, projections (tabular data payload), cards (self-contained data cards), and column_meta.
INVARIANT: Every block in a manifest MUST be frozen with a valid digest. The manifest is immutable once the edition is sealed.
Edition Snapshot (Sealed Decision)
An Edition Snapshot is the complete, sealed decision artifact: evidence manifest, narrative, attestation, and decision metadata in one verifiable record. See component.cortex.investigation-lifecycle#edition for the creation and sealing flow.
Edition Lifecycle
created (pending_review) ──freeze──▶ frozen ──attest──▶ attested
| Status | Meaning |
|---|---|
pending_review |
Edition created, evidence manifest assembled |
approved |
Review completed, ready for attestation |
rejected |
Review found issues |
attested |
Human has attested — edition is sealed |
Edition State Machine
States: { PENDING_REVIEW, APPROVED, REJECTED, ATTESTED } Initial: PENDING_REVIEW Terminal: ATTESTED
| From | To | Trigger | Preconditions |
|---|---|---|---|
| PENDING_REVIEW | APPROVED | review_close(approved) |
Reviewer authorized. All manifest blocks frozen. |
| PENDING_REVIEW | REJECTED | review_close(rejected) |
Reviewer authorized. rationale provided. |
| APPROVED | ATTESTED | attest |
content_hash computed. Attester ≠ author. actor.type = user. confirmations non-empty. |
| REJECTED | PENDING_REVIEW | revision |
New edition_number assigned (creates a new edition, not a mutation). |
Illegal: ATTESTED→Any, PENDING_REVIEW→ATTESTED (review mandatory), APPROVED→REJECTED.
INVARIANT: An attested edition is permanently sealed. No field may be modified after attestation. To supersede it, create a new edition with a higher edition_number.
Content Hash
content_hash = SHA256(canonical_json({insight_id, edition_number, evidence_manifest, narrative_snapshot, decision_metadata}))
INVARIANT: An edition MUST have a content_hash before it can be attested. The attestation's signature and content_hash_attested reference this hash. Any modification to the covered fields invalidates the attestation.
Attestation
An attestation is a human's commitment to a decision based on the evidence in the manifest.
INVARIANT: An attestation MUST reference the edition's content_hash. The attester commits to the evidence, narrative, and decision metadata as they existed at attestation time.
INVARIANT: The attester MUST differ from the edition's author (separation of duties).
Edition Fields Reference
| Field | Required | Description |
|---|---|---|
schema_version |
Yes | Schema version (integer) |
edition_id |
Yes | Unique identifier (edn_ prefix) |
insight_id |
Yes | Parent investigation |
create_ts |
Yes | ISO 8601 creation timestamp. Immutable once set. |
edition_number |
Yes | Sequential version number (≥ 1) |
head_event_id |
Yes | Event ledger head at creation time |
evidence_manifest |
Yes | Ordered array of frozen block entries with digests (see §manifest) |
created_by |
Yes | Actor who created the edition |
branch |
No | Branch name (default main) |
status |
No | pending_review, approved, rejected, attested (default pending_review) |
narrative_snapshot |
No | Sealed narrative (title, executive_summary, methodology, conclusion) |
decision_metadata |
No | Decision context (decision_type, decision_question, decision_template_id) |
review |
No | Review record (reviewer_id, status, outcome_type, rationale) |
attestation |
Attested | Attestation record — required when status = attested |
decision_tags |
No | Array of tag objects (tag_id, tag_name, tagged_by, tagged_at) |
content_hash |
Frozen | SHA-256 of edition content — required before attestation |
frozen_at |
Frozen | ISO 8601 timestamp when edition was frozen |
frozen_by |
Frozen | Actor who froze the edition |
The No-Action Pattern
DES requires recording deliberate inaction with the same evidentiary rigor as action. When an analyst reviews a signal, investigates, and determines no action is required, DES captures decision_metadata.decision_type: no_action plus a full attestation. The evidence manifest still contains the frozen blocks reviewed; the edition still requires attestation; the triggering signal is marked resolved.
INVARIANT: A no-action decision MUST include at least one evidence block in its manifest. "No action" is a decision, not the absence of one.
Regulators, auditors, and compliance teams need to answer "Why didn't you act?" The no-action pattern provides a verifiable answer: the right person reviewed the right evidence at the right time and made a deliberate, documented choice not to act.
Replay Semantics
DES supports full decision replay — reconstructing not just what was decided, but what the decider saw at decision time.
| Dimension | How DES Records It |
|---|---|
| What evidence existed | evidence_manifest with frozen blocks and digests |
| What the decider saw | materialization_mode: frozen + captured_at |
| What was not visible | outcome: PARTIAL or NO_DATA — what was available to that role |
| What narrative was written | narrative_snapshot in the edition |
| Who decided / when / what they committed to | attestation.attester_id + attester_role, attested_at, confirmations[] |
| Every action taken | Event ledger (append-only) |
Two users with different access levels may see different evidence from the same sources; DES handles this via the outcome field. Each user's edition reflects what they saw.
INVARIANT: The evidence chain is valid regardless of the viewer's access level. Integrity hashes are computed on the evidence as received, not on the unfiltered source.
Integrity Model
Hash Chain
Block structural content ──▶ block digest (SHA-256)
Block raw content ──▶ result_hash (SHA-256)
Edition core content ──▶ content_hash (SHA-256)
Attestation ──▶ signature = content_hash
Effect payload ──▶ payload_hash (SHA-256) [optional extension]
All hashes use canonical JSON: sorted keys, no extraneous whitespace, UTF-8 encoding, prefixed with sha256:.
result_hash = "sha256:" + SHA256(canonical_json(content))
block_digest = "sha256:" + SHA256(canonical_json({block_kind, projections, cards, column_meta}))
content_hash = "sha256:" + SHA256(canonical_json({insight_id, edition_number, evidence_manifest, narrative_snapshot, decision_metadata}))
payload_hash = "sha256:" + SHA256(canonical_json(effect_payload)) [optional extension]
Verification
Any party with access to the sealed edition can verify: each block's result_hash matches its content; each manifest entry's digest matches the block's structural content; the edition's content_hash matches its core fields; and the attestation's content_hash_attested matches the edition's content_hash. If any hash fails, the evidence chain is broken and the decision is flagged for review.
Accountability Model
DES defines a lightweight accountability model that constrains who can do what during an investigation. Implementations express accountability rules as configuration (packs, policies, roles) — not code. See component.cortex.pack-reference#accountability and component.cortex.investigation-lifecycle#accountability for enforcement points.
Accountability Constraints
| Constraint | Description |
|---|---|
| Entry modes | Which investigation modes are allowed for a role |
| Minimum evidence | Minimum pinned blocks before an edition can be created |
| Allowed decision types | Which decision outcomes a role can produce |
| Require rationale | Whether a narrative/rationale is mandatory |
| Attester role | Which roles are authorized to attest editions |
| Separation of duties | Attester must differ from author |
Decision Templates
A Decision Template defines the structure of an edition for a specific decision type: required evidence (minimum blocks, required block kinds), required narrative sections, whether attestation is required, and attestation rules (required roles, minimum attesters). Templates are referenced by accountability configuration, not hardcoded. See component.cortex.pack-reference#decision-template.
Actor Types
| Type | Description |
|---|---|
user |
A human participant (analyst, reviewer, attester) — may attest |
agent |
An AI agent acting on behalf of a user — requires on_behalf_of, MUST NOT attest |
system |
An automated process (signal computation, scheduled evaluation) — MUST NOT attest |
Multi-Agent Provenance
Investigations may involve multiple agents, each contributing blocks independently. DES requires every agent's contribution be individually traceable: each agent's blocks carry the agent's identity in the event actor field; each block has its own result_hash; the manifest lists blocks from all contributing agents; an auditor can reconstruct which agent produced which evidence, when, and under whose authority. Agent-to-agent delegation is recorded as separate ledger events.
INVARIANT: Regardless of how many agents participate, attestation remains human. Agents produce evidence. Humans commit to decisions.
Decision Effects (Optional Extension)
A sealed decision often requires execution beyond the decision system — sending a notice, filing a regulatory report, updating a loan system, dispatching a containment order. DES draws a strict boundary between deliberation (§block–§accountability) and execution. Effects are an informative extension; the core spec is self-contained. Implementation guidance for the pack system lives in component.cortex.task-and-effect#effect.
The Three Layers
| Layer | Objects | Purpose | When |
|---|---|---|---|
| A. Investigation | Blocks, Events, Tasks, Edition | Deliberation — gather evidence, make decision | Before sealing |
| B. Decision Artifact | Evidence manifest, Narrative, Content hash, Attestation | Sealed record — immutable, replayable | At sealing |
| C. Execution | Decision Effects, External acknowledgments | Execution — act on the decision | After sealing |
DES core covers Layers A and B. This section covers Layer C. The Effect object records that a sealed decision produced an outbound action and what happened — without prescribing how (no endpoint URLs, webhook configs, retry policies, routing instructions, or transport details).
Effect Types
| Type | Description |
|---|---|
external_dispatch |
Action sent to an external system (billing, logistics, CRM, regulatory) |
notification |
Informational notice — no completion expected |
human_process |
Action assigned to a person or team outside the decision system |
Effect Lifecycle
pending ──ack──▶ acknowledged ──complete──▶ completed
│ │
│ └──fail──▶ failed
│
└──timeout──▶ timed_out ──▶ Signal (escalation)
| Status | Meaning |
|---|---|
pending |
Effect created, awaiting acknowledgment |
acknowledged |
Target confirmed receipt |
completed |
Target confirmed successful execution |
failed |
Target reported failure (with reason) |
timed_out |
Deadline elapsed — generates escalation signal |
cancelled |
Effect withdrawn before completion |
INVARIANT: An effect MUST reference an attested edition via edition_id. Unattested decisions cannot generate effects.
INVARIANT: The payload_hash is computed from the effect payload at creation time. If later disputed, the hash proves what was sent.
Timeout and Escalation
When an effect's deadline passes without completed or failed: the system records an effect_timeout event; a new Signal (signal_type: effect_timeout, severity: high) is generated; the signal enters the standard OODA flow (Monitor → Investigate → Decide); the new investigation's entry_context is decision_driven, referencing the original edition. The full chain is traceable via correlation_id.
Federated Verification (Informative)
When both originating and target systems are DES-compliant, an effect acknowledgment MAY include cross-system hash references (external_reference, external_ledger_ref, completion_hash) pointing at the target system's own sealed edition. DES does not prescribe the federation protocol — only that cross-system references are recorded in the ledger.
Effect Fields Reference
| Field | Required | Description |
|---|---|---|
schema_version |
Yes | Schema version (integer) |
effect_id |
Yes | Unique identifier (eff_ prefix) |
edition_id |
Yes | The attested edition that produced this effect |
insight_id |
Yes | The investigation that produced the edition |
effect_type |
Yes | Type of effect (see §effect.types) |
target |
Yes | Target system or process (implementation-defined) |
action |
No | Human-readable action label |
payload_hash |
Yes | SHA-256 hash of the effect payload |
payload_summary |
No | Human-readable summary of what was sent |
status |
Yes | Current lifecycle status (see §effect.lifecycle) |
deadline |
No | ISO 8601 deadline for completion |
created_at |
Yes | ISO 8601 creation timestamp |
created_by |
Yes | Actor who created the effect |
correlation_id |
No | Event ID linking to the effect_created ledger entry |
completed_at |
No | ISO 8601 completion timestamp |
failure_reason |
No | Reason for failure (when status is failed) |
external_reference |
No | Reference ID from the external system |
Conformance Levels
- Level 1 — Evidence Capture: Block schema; all 5 block kinds; 3-stage lifecycle;
result_hashon frozen blocks; prefixed identifiers. - Level 2 — Decision Sealing: Level 1 plus Edition and Investigation schemas; evidence manifests with digests; attestation records with
content_hashverification; append-only event ledger. - Level 3 — Full Compliance: Level 2 plus no-action pattern; replay semantics; cross-visibility evidence chains; accountability constraints; decision templates.
- Level 4 — Decision Effects (Optional): Level 3 plus Effect schema; effect lifecycle; effect ledger events; timeout signals; federated hash references (informative).
What DES Is Not
DES is deliberately minimal. It does NOT define: runtime/execution engine, UI/visualization, storage backend, authentication/authorization mechanism, network protocol/API surface, workflow orchestration, AI/ML model requirements, access-control policy language, external system APIs, dispatch routing, or agent communication protocols. Implementors choose their own stack; DES defines the evidence artifacts and their integrity contracts.
Depends on: component.cortex.intelligence
Realizes: product.block, product.edition, product.investigation, product.signal, product.task
Required by: component.conduit.effect-engine, component.cortex.developer-rules, component.cortex.investigation-lifecycle, component.cortex.platform-architecture, component.cortex.signal-lifecycle, component.cortex.task-and-effect