# RFC 0051: Global Perspective & Tension Tracking

| | |
|---|---|
| **Status** | Accepted |
| **Date** | 2026-02-02 |
| **ADRs** | 0014 (Alignment Dialogue Agents), 0005 (Single Source), 0018 (DynamoDB-Portable Schema) |
| **Extends** | RFC 0048 (Expert Pools), RFC 0050 (Graduated Rotation) |
| **Extended By** | RFC 0054 (Calibrated Alignment — Ethos & Tenets) |
| **Dialogue** | 2047 (5 experts, 3 rounds, ALIGNMENT 427) |

---

## Summary

The alignment dialogue system currently tracks perspectives and tensions within round summaries, making cross-dialogue analysis difficult. This RFC introduces **global perspective and tension tracking** with:

1. **Two-phase ID assignment**: Agents write local IDs (`MUFFIN-P0001`), Judge registers with global IDs (`P0001`)
2. **Global IDs**: `P0001`, `R0001`, `T0001` — sequential per round, expert in data not ID
3. **DB-first architecture**: All data registered via MCP tools, agents get context from DB
4. **First-class entities**: Perspectives (P), recommendations (R), tensions (T), evidence (E), claims (C) with full lifecycle
5. **LLM-friendly transcripts**: MCP generates markdown context, writes to disk for debugging
6. **Dynamic expert creation**: Judge can create experts mid-dialogue to address emerging needs
7. **JSON export**: Full provenance from database queries (no file parsing)
8. **Calibration support**: Optional ethos integration for calibrated dialogues (see RFC 0054)

## Problem

In the NVIDIA Investment Decision dialogue:
- 24 perspectives surfaced across 3 rounds from 12 experts
- 12 tensions raised and resolved
- **No global numbering**: P01 in round 0 vs P01 in round 1 are ambiguous
- **No origin tracking**: "Who said this?" requires reading full transcripts
- **No lifecycle visibility**: When was T0003 resolved? By whom?

The reference export format (`dialogue.json`) lacks these fields, making it unsuitable for:
- Cross-dialogue analysis
- Visualization dashboards
- Audit and compliance review

## Design

### Core Principle: Two-Phase ID Assignment

**Phase 1 — Agents write with local IDs:** `{UPPER(expert)}-{TYPE}{round:02d}{seq:02d}`
```markdown
[MUFFIN-P0001: Income mandate mismatch]
[DONUT-R0001: Options collar]
[MUFFIN-T0001: Growth vs income]
[MUFFIN-E0001: Historical IV data]
[MUFFIN-C0001: Income gap is bridgeable]
```

**Phase 2 — Judge registers, MCP assigns global IDs:**
```
P0001, P0002, P0003...       (perspectives, sequential per round)
R0001, R0002...              (recommendations, sequential per round)
T0001, T0002...              (tensions, sequential per round)
E0001, E0002...              (evidence, sequential per round)
C0001, C0002...              (claims, sequential per round)
```

**Storage key:** `(dialogue_id, round, seq)` with `expert_slug` as attribution

**Display ID:** `P{round:02d}{seq:02d}` — first 2 digits = round, last 2 digits = seq
- `P0001` = round 0, seq 1
- `P0102` = round 1, seq 2
- `P0215` = round 2, seq 15

Expert attribution is stored in the record, not encoded in the ID. All downstream references use global IDs.

### Schema

```sql
-- ================================================================
-- DIALOGUES (root table - enforces unique dialogue_id)
-- ================================================================
CREATE TABLE dialogues (
  dialogue_id     TEXT PRIMARY KEY,  -- slug derived from title
  title           TEXT NOT NULL,
  question        TEXT,
  status          TEXT NOT NULL DEFAULT 'open',
  created_at      TEXT NOT NULL,
  converged_at    TEXT,
  total_rounds    INT DEFAULT 0,
  total_alignment INT DEFAULT 0,
  output_dir      TEXT,              -- /tmp/blue-dialogue/{slug}

  -- Calibration (RFC 0054)
  calibrated      BOOLEAN DEFAULT FALSE,
  domain_id       TEXT,              -- FK to domains table (RFC 0054)
  ethos_id        TEXT,              -- FK to ethos table (RFC 0054)

  CHECK (status IN ('open', 'converging', 'converged', 'abandoned'))
);

-- ================================================================
-- VERDICTS (first-class entities, supports multiple per dialogue)
-- ================================================================
CREATE TABLE verdicts (
  dialogue_id     TEXT NOT NULL,
  verdict_id      TEXT NOT NULL,     -- V01, V02, or slug like "final", "minority"
  verdict_type    TEXT NOT NULL,     -- interim | final | minority | dissent
  round           INT  NOT NULL,     -- round when verdict was issued
  author_expert   TEXT,              -- expert who authored (null = Judge)
  recommendation  TEXT NOT NULL,     -- one-line decision
  description     TEXT NOT NULL,     -- reasoning summary (2-3 sentences)
  conditions      JSON,              -- ["condition1", "condition2"]
  vote            TEXT,              -- "11-1", "unanimous"
  confidence      TEXT,              -- unanimous | strong | split | contested
  tensions_resolved JSON,            -- ["T0001", "T0002"]
  tensions_accepted JSON,            -- ["T0006"] - acknowledged but not blocking
  recommendations_adopted JSON,      -- ["R0001"]
  key_evidence    JSON,              -- ["E0001", "E0101"] - evidence supporting verdict
  key_claims      JSON,              -- ["C0001", "C0101"] - claims adopted in verdict
  supporting_experts JSON,           -- ["muffin", "cupcake", ...] for minority verdicts

  -- Ethos compliance (RFC 0054) — only for calibrated dialogues
  ethos_compliance JSON,             -- {"fully_compliant": bool, "exceptions": [...], "violations": [...]}

  created_at      TEXT NOT NULL,
  PRIMARY KEY (dialogue_id, verdict_id),
  FOREIGN KEY (dialogue_id) REFERENCES dialogues(dialogue_id),
  CHECK (verdict_type IN ('interim', 'final', 'minority', 'dissent'))
);

-- Prevent exact duplicate titles at same timestamp
CREATE UNIQUE INDEX idx_dialogues_title_created
  ON dialogues(title, created_at);

-- ================================================================
-- EXPERTS (participation and scores per dialogue)
-- ================================================================
CREATE TABLE experts (
  dialogue_id   TEXT NOT NULL,
  expert_slug   TEXT NOT NULL,     -- muffin, cupcake, etc. (capitalize for display)
  role          TEXT NOT NULL,     -- Value Analyst, Risk Manager, etc.
  description   TEXT,              -- detailed role description
  focus         TEXT,              -- brief focus area
  tier          TEXT NOT NULL,     -- Core, Adjacent, Wildcard
  source        TEXT NOT NULL,     -- pool | created
  relevance     REAL,              -- 0.0-1.0 (from pool, or Judge-assigned for created)
  creation_reason TEXT,            -- why Judge created this expert (null if from pool)
  color         TEXT,              -- hex color for UI
  scores        JSON,              -- {"0": 12, "1": 8, "2": 15} - per-round scores
  raw_content   JSON,              -- {"0": "markdown...", "1": "markdown..."} - per-round responses
  total_score   INT DEFAULT 0,     -- computed: sum of scores (denormalized)
  first_round   INT,               -- round when expert first participated
  created_at    TEXT NOT NULL,
  PRIMARY KEY (dialogue_id, expert_slug),
  FOREIGN KEY (dialogue_id) REFERENCES dialogues(dialogue_id),
  CHECK (tier IN ('Core', 'Adjacent', 'Wildcard')),
  CHECK (source IN ('pool', 'created'))
);

-- ================================================================
-- ROUNDS (metadata and scores per round)
-- ================================================================
CREATE TABLE rounds (
  dialogue_id   TEXT NOT NULL,
  round         INT  NOT NULL,
  title         TEXT,              -- "Opening Arguments", "Refinement", etc.
  score         INT  NOT NULL,     -- ALIGNMENT score for this round
  summary       TEXT,              -- Judge's synthesis
  status        TEXT NOT NULL DEFAULT 'open',
  created_at    TEXT NOT NULL,
  completed_at  TEXT,
  PRIMARY KEY (dialogue_id, round),
  FOREIGN KEY (dialogue_id) REFERENCES dialogues(dialogue_id),
  CHECK (status IN ('open', 'in_progress', 'completed'))
);

-- ================================================================
-- PERSPECTIVES
-- ================================================================
CREATE TABLE perspectives (
  dialogue_id    TEXT NOT NULL,
  round          INT  NOT NULL,     -- origin round
  seq            INT  NOT NULL,     -- global per round (P0001, P0002...)
  label          TEXT NOT NULL,
  content        TEXT NOT NULL,     -- Judge-synthesized content
  contributors   JSON NOT NULL,     -- ["muffin", "cupcake"] - all who contributed
  status         TEXT NOT NULL DEFAULT 'open',
  references     JSON,              -- [{"type": "refine", "target": "P0001"}, ...]
  created_at     TEXT NOT NULL,
  PRIMARY KEY (dialogue_id, round, seq),
  FOREIGN KEY (dialogue_id) REFERENCES dialogues(dialogue_id),
  CHECK (status IN ('open', 'refined', 'conceded', 'merged'))
);

-- Perspective events (audit trail)
CREATE TABLE perspective_events (
  dialogue_id       TEXT NOT NULL,
  perspective_round INT  NOT NULL,
  perspective_seq   INT  NOT NULL,
  event_type        TEXT NOT NULL,  -- created, refined, conceded, merged
  event_round       INT  NOT NULL,  -- round when event occurred
  actors            JSON NOT NULL,  -- ["muffin"] - who triggered this event
  result_id         TEXT,           -- e.g., "P0101" if refined into new perspective
  created_at        TEXT NOT NULL,
  PRIMARY KEY (dialogue_id, perspective_round, perspective_seq, created_at),
  FOREIGN KEY (dialogue_id, perspective_round, perspective_seq)
    REFERENCES perspectives(dialogue_id, round, seq),
  CHECK (event_type IN ('created', 'refined', 'conceded', 'merged'))
);

CREATE INDEX idx_perspectives_dialogue_round
  ON perspectives(dialogue_id, round, created_at);

-- ================================================================
-- TENSIONS
-- ================================================================
CREATE TABLE tensions (
  dialogue_id      TEXT NOT NULL,
  round            INT  NOT NULL,    -- origin round
  seq              INT  NOT NULL,    -- global per round (T0001, T0002...)
  label            TEXT NOT NULL,
  description      TEXT NOT NULL,    -- Judge-synthesized description
  contributors     JSON NOT NULL,    -- ["muffin", "cupcake"] - all who surfaced this
  status           TEXT NOT NULL DEFAULT 'open',
  references       JSON,             -- [{"type": "depend", "target": "P0001"}, ...]
  created_at       TEXT NOT NULL,
  PRIMARY KEY (dialogue_id, round, seq),
  FOREIGN KEY (dialogue_id) REFERENCES dialogues(dialogue_id),
  CHECK (status IN ('open', 'addressed', 'resolved', 'reopened'))
);

-- Display ID: T{round:02d}{seq:02d}
-- e.g., T0001, T0102

CREATE INDEX idx_tensions_status ON tensions(dialogue_id, status);

-- ================================================================
-- MOVES (dialogue moves: defend, challenge, bridge, etc.)
-- ================================================================
CREATE TABLE moves (
  dialogue_id   TEXT NOT NULL,
  round         INT  NOT NULL,
  seq           INT  NOT NULL,
  expert_slug   TEXT NOT NULL,
  move_type     TEXT NOT NULL,       -- defend, challenge, bridge, request, concede, converge
  targets       JSON NOT NULL,       -- ["P0001", "R0001"] - IDs this move references
  context       TEXT,                -- brief explanation
  created_at    TEXT NOT NULL,
  PRIMARY KEY (dialogue_id, round, expert_slug, seq),
  FOREIGN KEY (dialogue_id) REFERENCES dialogues(dialogue_id),
  CHECK (move_type IN ('defend', 'challenge', 'bridge', 'request', 'concede', 'converge'))
);

-- ================================================================
-- RECOMMENDATIONS (first-class, links to tensions and perspectives)
-- ================================================================
CREATE TABLE recommendations (
  dialogue_id        TEXT NOT NULL,
  round              INT  NOT NULL,   -- origin round
  seq                INT  NOT NULL,   -- global per round (R0001, R0002...)
  label              TEXT NOT NULL,
  content            TEXT NOT NULL,   -- Judge-synthesized content
  contributors       JSON NOT NULL,   -- ["donut", "muffin"] - all who contributed
  parameters         JSON,            -- structured data (e.g., options parameters)
  status             TEXT NOT NULL DEFAULT 'proposed',
  references         JSON,            -- [{"type": "refine", "target": "R0001"}, {"type": "address", "target": "T0001"}, ...]
  adopted_in_verdict TEXT,            -- verdict_id if adopted
  created_at         TEXT NOT NULL,
  PRIMARY KEY (dialogue_id, round, seq),
  FOREIGN KEY (dialogue_id) REFERENCES dialogues(dialogue_id),
  CHECK (status IN ('proposed', 'amended', 'adopted', 'rejected'))
);

-- Recommendation events (audit trail)
CREATE TABLE recommendation_events (
  dialogue_id     TEXT NOT NULL,
  rec_round       INT  NOT NULL,
  rec_seq         INT  NOT NULL,
  event_type      TEXT NOT NULL,   -- created, amended, adopted, rejected
  event_round     INT  NOT NULL,
  actors          JSON NOT NULL,   -- who triggered this event
  result_id       TEXT,            -- new recommendation ID if amended
  created_at      TEXT NOT NULL,
  PRIMARY KEY (dialogue_id, rec_round, rec_seq, created_at),
  FOREIGN KEY (dialogue_id, rec_round, rec_seq)
    REFERENCES recommendations(dialogue_id, round, seq),
  CHECK (event_type IN ('created', 'amended', 'adopted', 'rejected'))
);

-- Display ID: R{round:02d}{seq:02d}
-- e.g., R0001, R0102

CREATE INDEX idx_recommendations_status
  ON recommendations(dialogue_id, status);

-- ================================================================
-- EVIDENCE (first-class: data, precedents, facts)
-- ================================================================
CREATE TABLE evidence (
  dialogue_id    TEXT NOT NULL,
  round          INT  NOT NULL,
  seq            INT  NOT NULL,     -- global per round (E0001, E0002...)
  label          TEXT NOT NULL,
  content        TEXT NOT NULL,     -- the data/facts
  contributors   JSON NOT NULL,     -- ["muffin"]
  status         TEXT NOT NULL DEFAULT 'cited',
  references     JSON,              -- [{"type": "support", "target": "P0001"}]
  created_at     TEXT NOT NULL,
  PRIMARY KEY (dialogue_id, round, seq),
  FOREIGN KEY (dialogue_id) REFERENCES dialogues(dialogue_id),
  CHECK (status IN ('cited', 'challenged', 'confirmed', 'refuted'))
);

-- Display ID: E{round:02d}{seq:02d}
-- e.g., E0001, E0103

CREATE INDEX idx_evidence_status
  ON evidence(dialogue_id, status);

-- ================================================================
-- CLAIMS (first-class: quotable position statements)
-- ================================================================
CREATE TABLE claims (
  dialogue_id    TEXT NOT NULL,
  round          INT  NOT NULL,
  seq            INT  NOT NULL,     -- global per round (C0001, C0002...)
  label          TEXT NOT NULL,
  content        TEXT NOT NULL,     -- the claim statement
  contributors   JSON NOT NULL,     -- ["muffin"]
  status         TEXT NOT NULL DEFAULT 'asserted',
  references     JSON,              -- [{"type": "depend", "target": "P0001"}]
  created_at     TEXT NOT NULL,
  PRIMARY KEY (dialogue_id, round, seq),
  FOREIGN KEY (dialogue_id) REFERENCES dialogues(dialogue_id),
  CHECK (status IN ('asserted', 'supported', 'opposed', 'adopted', 'withdrawn'))
);

-- Display ID: C{round:02d}{seq:02d}
-- e.g., C0001, C0205

CREATE INDEX idx_claims_status
  ON claims(dialogue_id, status);

-- ================================================================
-- REFS (explicit cross-references between entities)
-- ================================================================
CREATE TABLE refs (
  dialogue_id   TEXT NOT NULL,
  source_type   TEXT NOT NULL,     -- P, R, T, E, C
  source_id     TEXT NOT NULL,     -- P0101, R0001, etc.
  ref_type      TEXT NOT NULL,     -- support, oppose, refine, address, resolve, reopen, question, depend
  target_type   TEXT NOT NULL,     -- P, R, T, E, C
  target_id     TEXT NOT NULL,     -- P0001, T0001, etc.
  created_at    TEXT NOT NULL,
  PRIMARY KEY (dialogue_id, source_id, ref_type, target_id),
  FOREIGN KEY (dialogue_id) REFERENCES dialogues(dialogue_id),

  -- Type enum constraints
  CHECK (source_type IN ('P', 'R', 'T', 'E', 'C')),
  CHECK (target_type IN ('P', 'R', 'T', 'E', 'C')),
  CHECK (ref_type IN ('support', 'oppose', 'refine', 'address', 'resolve', 'reopen', 'question', 'depend')),

  -- Type consistency: source_type must match source_id prefix
  CHECK (
    (source_type = 'P' AND source_id LIKE 'P%') OR
    (source_type = 'R' AND source_id LIKE 'R%') OR
    (source_type = 'T' AND source_id LIKE 'T%') OR
    (source_type = 'E' AND source_id LIKE 'E%') OR
    (source_type = 'C' AND source_id LIKE 'C%')
  ),

  -- Type consistency: target_type must match target_id prefix
  CHECK (
    (target_type = 'P' AND target_id LIKE 'P%') OR
    (target_type = 'R' AND target_id LIKE 'R%') OR
    (target_type = 'T' AND target_id LIKE 'T%') OR
    (target_type = 'E' AND target_id LIKE 'E%') OR
    (target_type = 'C' AND target_id LIKE 'C%')
  ),

  -- Semantic constraints: which ref_types are valid for which targets
  CHECK (
    -- Tension-only targets: resolve, reopen, address must target T
    (ref_type IN ('resolve', 'reopen', 'address') AND target_type = 'T') OR
    -- Same-type only: refine must be source_type = target_type
    (ref_type = 'refine' AND source_type = target_type) OR
    -- Flexible: support, oppose, question, depend can target anything
    (ref_type IN ('support', 'oppose', 'question', 'depend'))
  )
);

-- Query: "What supports P0001?"
CREATE INDEX idx_refs_target
  ON refs(dialogue_id, target_id, ref_type);

-- Query: "What does P0101 reference?"
CREATE INDEX idx_refs_source
  ON refs(dialogue_id, source_id);

-- ================================================================
-- TENSION_EVENTS (lifecycle audit trail)
-- ================================================================
CREATE TABLE tension_events (
  dialogue_id    TEXT NOT NULL,
  tension_round  INT  NOT NULL,   -- round of the tension
  tension_seq    INT  NOT NULL,   -- seq of the tension
  event_type     TEXT NOT NULL,
  event_round    INT  NOT NULL,   -- round when event occurred
  actors         JSON NOT NULL,   -- ["muffin", "donut"] - who triggered this
  reason         TEXT,
  reference      TEXT,            -- global ID of resolving item (e.g., "P0005", "R0001")
  created_at     TEXT NOT NULL,
  PRIMARY KEY (dialogue_id, tension_round, tension_seq, created_at),
  FOREIGN KEY (dialogue_id, tension_round, tension_seq)
    REFERENCES tensions(dialogue_id, round, seq),
  CHECK (event_type IN ('created', 'addressed', 'resolved', 'reopened', 'commented'))
);
```

### Dialogue ID Collision Handling

The `dialogue_id` is derived from the title via slugification. Collisions are handled at creation time:

```
Algorithm: generate_dialogue_id(title)
  1. slug = slugify(title)  // "NVIDIA Analysis" → "nvidia-analysis"
  2. IF NOT EXISTS(SELECT 1 FROM dialogues WHERE dialogue_id = slug):
       RETURN slug
  3. FOR i IN 1..99:
       candidate = slug + "-" + i  // "nvidia-analysis-2"
       IF NOT EXISTS(SELECT 1 FROM dialogues WHERE dialogue_id = candidate):
         RETURN candidate
  4. FAIL "Too many dialogues with similar titles"
```

**Output directory** follows the same pattern:
- `/tmp/blue-dialogue/{dialogue_id}/`

This ensures:
- No file system collisions between concurrent dialogues
- Deterministic ID generation (same title → same base slug)
- Human-readable IDs (not UUIDs)

### Tension Lifecycle

```
                    ┌──────────────┐
                    │   created    │
                    └──────┬───────┘
                           │
                           ▼
                    ┌──────────────┐
           ┌───────►│    open      │◄───────┐
           │        └──────┬───────┘        │
           │               │                │
           │               ▼                │
           │        ┌──────────────┐        │
           │        │  addressed   │────────┤
           │        └──────┬───────┘        │
           │               │                │
           │               ▼                │
           │        ┌──────────────┐        │
           └────────│   resolved   │────────┘
                    └──────────────┘
                           │
                           ▼ (if insufficient)
                    ┌──────────────┐
                    │   reopened   │
                    └──────────────┘
```

**Authority Rules:**
- Any expert can propose `addressed` with a resolution mechanism
- Original author or facilitator confirms `resolved`
- Reopening creates an event, preserving full history

### JSON Export Format

```json
{
  "id": "nvidia-investment-decision",
  "title": "NVIDIA Investment Analysis",
  "date": "2026-02-02",
  "status": "converged",
  "totalAlignment": 423,

  // Calibration (RFC 0054) — omitted if uncalibrated
  "calibration": {
    "calibrated": true,
    "domain": "fiduciary-investment",
    "ethos_id": "ethos-nvidia-001",
    "rules_count": 14,
    "compliance": {
      "fully_compliant": false,
      "exceptions": 1,
      "violations": 0
    }
  },

  "experts": [
    {
      "slug": "muffin",             // capitalize for display: "Muffin"
      "role": "Value Analyst",
      "tier": "Core",
      "scores": {
        "0": 12,
        "1": 8,
        "2": 15
      },
      "total": 35
    },
    {
      "slug": "palmier",
      "role": "Geopolitical Risk Analyst",
      "tier": "Adjacent",
      "source": "created",          // joined mid-dialogue
      "scores": {
        "2": 14                     // only present in round 2
      },
      "total": 14
    }
  ],

  "rounds_data": [
    {
      "round": 0,
      "score": 117,
      "experts": {
        "muffin": {
          "score": 12,
          "actions": [
            { "type": "perspective", "action": "created", "id": "P0001" },
            { "type": "tension", "action": "created", "id": "T0001" }
          ]
        },
        "cupcake": {
          "score": 10,
          "actions": [
            { "type": "perspective", "action": "created", "id": "P0002" },
            { "type": "tension", "action": "created", "id": "T0002" }
          ]
        },
        "donut": {
          "score": 15,
          "actions": [
            { "type": "perspective", "action": "created", "id": "P0003" },
            { "type": "recommendation", "action": "created", "id": "R0001" }
          ]
        }
      }
    },
    {
      "round": 1,
      "score": 45,
      "experts": {
        "muffin": {
          "score": 8,
          "actions": [
            { "type": "perspective", "action": "refined", "id": "P0101", "refines": "P0001" },
            { "type": "tension", "action": "addressed", "id": "T0001", "via": "R0001" }
          ]
        },
        "donut": {
          "score": 10,
          "actions": [
            { "type": "recommendation", "action": "amended", "id": "R0101", "amends": "R0001" },
            { "type": "tension", "action": "resolved", "id": "T0002", "via": "P0101" }
          ]
        }
      }
    }
  ],

  "perspectives": [
    {
      "id": "P0001",
      "label": "Income mandate mismatch",
      "content": "NVIDIA's zero dividend conflicts with 4% income requirement...",
      "status": "refined",
      "origin": {
        "round": 0,
        "contributors": ["muffin", "cupcake"]  // Judge synthesized from both
      },
      "events": [
        { "type": "created", "round": 0, "by": ["muffin", "cupcake"] },
        { "type": "refined", "round": 1, "by": ["muffin"], "result": "P0101" }
      ]
    }
  ],

  "tensions": [
    {
      "id": "T0001",
      "label": "Growth vs income obligation",
      "description": "NVIDIA's zero dividend conflicts with trust's 4% income requirement",
      "status": "resolved",
      "origin": {
        "round": 0,
        "contributors": ["muffin", "cupcake"]
      },
      "events": [
        { "type": "created", "round": 0, "by": ["muffin", "cupcake"] },
        { "type": "addressed", "round": 1, "by": ["donut"], "reference": "R0001" },
        { "type": "resolved", "round": 2, "by": ["muffin"], "reference": "P0201" }
      ],
      "relatedPerspectives": ["P0001", "P0003"]
    }
  ],

  "recommendations": [
    {
      "id": "R0001",
      "label": "Income Collar Structure",
      "content": "Strike Selection Framework with 30-delta covered calls...",
      "parameters": {
        "covered_call_delta": "0.20-0.25",
        "protective_put_delta": "-0.15",
        "dte": "30-45"
      },
      "status": "adopted",
      "origin": {
        "round": 0,
        "contributors": ["donut"]
      },
      "events": [
        { "type": "created", "round": 0, "by": ["donut"] },
        { "type": "amended", "round": 1, "by": ["donut", "muffin"], "result": "R0101" },
        { "type": "adopted", "round": 2, "by": ["judge"], "reference": "verdict-final" }
      ],
      "addresses_tensions": ["T0001"],
      "builds_on": ["P0001"]
    }
  ],

  "evidence": [
    {
      "id": "E0001",
      "label": "Historical options premium data",
      "content": "NVDA 30-day ATM IV averaged 45% over past 24 months. 30-delta calls yielded 2.1-2.8% monthly premium.",
      "status": "confirmed",
      "origin": {
        "round": 1,
        "contributors": ["muffin"]
      },
      "events": [
        { "type": "cited", "round": 1, "by": ["muffin"] },
        { "type": "confirmed", "round": 2, "by": ["donut", "brioche"] }
      ],
      "supports": ["P0101", "R0001"]
    },
    {
      "id": "E0002",
      "label": "Trust covenant constraints",
      "content": "Section 4.2 requires minimum 4% annual distribution. Corpus preservation clause limits equity drawdown to 15%.",
      "status": "confirmed",
      "origin": {
        "round": 0,
        "contributors": ["cupcake"]
      },
      "events": [
        { "type": "cited", "round": 0, "by": ["cupcake"] },
        { "type": "confirmed", "round": 1, "by": ["muffin"] }
      ],
      "supports": ["T0001"]
    }
  ],

  "claims": [
    {
      "id": "C0001",
      "label": "Income mandate resolved via options",
      "content": "The 4% income mandate can be satisfied through covered call premium generation, eliminating the primary objection to NVDA exposure.",
      "status": "adopted",
      "origin": {
        "round": 1,
        "contributors": ["muffin"]
      },
      "events": [
        { "type": "asserted", "round": 1, "by": ["muffin"] },
        { "type": "supported", "round": 2, "by": ["donut", "brioche"] },
        { "type": "adopted", "round": 2, "by": ["judge"], "reference": "verdict-final" }
      ],
      "depends_on": ["E0001", "P0101", "R0001"]
    },
    {
      "id": "C0002",
      "label": "Concentration risk manageable with phased entry",
      "content": "Geographic and sector concentration concerns are mitigated by a 6-month phased entry strategy.",
      "status": "adopted",
      "origin": {
        "round": 2,
        "contributors": ["cupcake", "muffin"]
      },
      "events": [
        { "type": "asserted", "round": 2, "by": ["cupcake"] },
        { "type": "supported", "round": 2, "by": ["muffin"] },
        { "type": "adopted", "round": 2, "by": ["judge"], "reference": "verdict-final" }
      ],
      "depends_on": ["P0003", "T0002"]
    }
  ]
}
```

### MCP Server Integration

**Public tools (Judge-facing API):**

| Tool | Purpose |
|------|---------|
| `blue_dialogue_create` | Start dialogue with expert pool; returns Judge Protocol |
| `blue_dialogue_round_context` | **Bulk fetch** structured data for all panel experts in one call |
| `blue_dialogue_expert_create` | Create new expert mid-dialogue to address emerging needs |
| `blue_dialogue_round_register` | **Bulk register** all round data in single call (perspectives, recommendations, tensions, evidence, claims, refs, scores) |
| `blue_dialogue_verdict_register` | Register a verdict (interim, final, minority, dissent) |
| `blue_dialogue_export` | Generate JSON export from database (no file parsing) |

**Internal functions (not exposed as MCP tools):**

These are implementation details called by the bulk tools above:

| Function | Called By |
|----------|-----------|
| `perspective_register` | `round_register` |
| `recommendation_register` | `round_register` |
| `tension_register` | `round_register` |
| `tension_update` | `round_register` |
| `evidence_register` | `round_register` |
| `claim_register` | `round_register` |
| `ref_register` | `round_register` |
| `recommendation_update` | `round_register`, `verdict_register` |

This gives the Judge a clean 6-tool API while maintaining internal composability.

**Defaults (Judge discretion unless user overrides):**

| Parameter | Default | User Override |
|-----------|---------|---------------|
| Panel size | Judge selects based on domain complexity | "Use 8 experts" |
| Convergence | 100% (all tensions resolved, all experts agree) | "Run to 80% convergence" |

**100% convergence** means:
- All tensions resolved or explicitly accepted
- All experts agree with the verdict (no dissenters)

Users can request early termination or partial convergence for faster results.

**Verdict tool parameters:**

```json
{
  "dialogue_id": "nvidia-decision",
  "verdict_id": "final",           // or "V01", "minority-esg"
  "verdict_type": "final",         // interim | final | minority | dissent
  "round": 3,
  "author_expert": null,           // null = Judge, or expert slug
  "recommendation": "REJECT full swap. APPROVE conditional partial trim.",
  "description": "The panel unanimously rejected a full NVAI-to-NVDA swap due to income mandate mismatch...",
  "conditions": [
    "Execute 60-90 days post-refinancing",
    "Implement 30-delta covered calls"
  ],
  "vote": "12-0",
  "confidence": "unanimous",
  "tensions_resolved": ["T0001", "T0002", "T0003"],
  "tensions_accepted": ["T0006"],
  "recommendations_adopted": ["R0001"],
  "supporting_experts": null       // for minority verdicts: ["churro", "eclair"]
}
```

**Verdict types:**

| Type | Use Case |
|------|----------|
| `interim` | Checkpoint verdict mid-dialogue (e.g., "continue with options exploration") |
| `final` | Authoritative conclusion when dialogue converges |
| `minority` | Structured dissent from subset of experts |
| `dissent` | Single expert's formal objection with reasoning |

**Bulk round registration** (`blue_dialogue_round_register`):

Register all round data in a single call — perspectives, recommendations, tensions, evidence, claims, scores, and events:

```json
{
  "dialogue_id": "nvidia-decision",
  "round": 1,
  "score": 45,
  "summary": "Panel converging on conditional approval with options overlay...",

  "expert_scores": {
    "muffin": 8,
    "donut": 10,
    "cupcake": 7
  },

  "perspectives": [
    {
      "local_id": "MUFFIN-P0101",
      "label": "Options viability confirmed",
      "content": "The 30-delta covered call strategy...",
      "contributors": ["muffin"],
      "references": [
        { "type": "refine", "target": "P0001" },
        { "type": "support", "target": "R0001" },
        { "type": "address", "target": "T0001" }
      ]
    },
    {
      "local_id": "CUPCAKE-P0101",
      "label": "Concentration risk mitigated",
      "content": "Phased entry over 6 months...",
      "contributors": ["cupcake", "scone"],
      "references": [
        { "type": "address", "target": "T0002" }
      ]
    }
  ],

  "recommendations": [
    {
      "local_id": "DONUT-R0101",
      "label": "Amended collar structure",
      "content": "Updated strike selection...",
      "contributors": ["donut", "muffin"],
      "parameters": { "delta": "0.25", "dte": "45" },
      "references": [
        { "type": "refine", "target": "R0001" },
        { "type": "address", "target": "T0001" },
        { "type": "depend", "target": "MUFFIN-P0101" }
      ]
    }
  ],

  "tensions": [
    {
      "local_id": "CROISSANT-T0101",
      "label": "Execution timing",
      "description": "Post-refinancing window constraint",
      "contributors": ["croissant"],
      "references": [
        { "type": "depend", "target": "R0001" }
      ]
    }
  ],

  "evidence": [
    {
      "local_id": "MUFFIN-E0101",
      "label": "Historical options premium data",
      "content": "NVDA 30-day ATM IV averaged 45% over past 24 months. 30-delta calls yielded 2.1-2.8% monthly premium.",
      "contributors": ["muffin"],
      "references": [
        { "type": "support", "target": "MUFFIN-P0101" }
      ]
    }
  ],

  "claims": [
    {
      "local_id": "MUFFIN-C0101",
      "label": "Income mandate resolved",
      "content": "The income mandate objection is resolved via options overlay. Remaining concerns are execution timing and concentration—both manageable.",
      "contributors": ["muffin"],
      "references": [
        { "type": "depend", "target": "MUFFIN-P0101" },
        { "type": "depend", "target": "MUFFIN-E0101" }
      ]
    }
  ],

  "moves": [
    { "expert": "muffin", "type": "bridge", "targets": ["P0003", "R0001"], "context": "Reconciling concentration and collar" },
    { "expert": "donut", "type": "defend", "target": "R0001", "context": "Liquidity supports execution" }
  ],

  "tension_updates": [
    { "id": "T0001", "status": "addressed", "by": ["donut"], "via": "DONUT-R0101" },
    { "id": "T0002", "status": "resolved", "by": ["cupcake"], "via": "CUPCAKE-P0101" }
  ]
}
```

**Local ID format:** `{UPPER(expert)}-{TYPE}{round:02d}{seq:02d}`
- Perspectives: `MUFFIN-P0101`, `CUPCAKE-P0102`
- Proposals: `DONUT-R0101`, `MUFFIN-R0103`
- Tensions: `CROISSANT-T0101`, `SCONE-T0201`
- Evidence: `MUFFIN-E0101`, `DONUT-E0102`
- Claims: `MUFFIN-C0101`, `CUPCAKE-C0102`

**Resolution:**
- MCP resolves local IDs → global IDs before storing
- **Input**: Links can reference local IDs (same batch) or global IDs (prior rounds)
- **Storage**: All links stored with global IDs only (MCP resolves local refs)
- Return includes mapping: `local_id` → `global_id`

```json
```

**MCP resolves local IDs, assigns global IDs, returns mapping:**

Note: Local seq is expert-local, global seq is dialogue-global. Three experts each writing their "first" perspective (local `01`) get global `01`, `02`, `03`:

```json
{
  "round": 1,
  "id_mapping": {
    "MUFFIN-P0101": "P0101",     // Muffin's 1st → global 1st
    "CUPCAKE-P0101": "P0102",    // Cupcake's 1st → global 2nd
    "SCONE-P0101": "P0103",      // Scone's 1st → global 3rd
    "DONUT-R0101": "R0101",
    "CROISSANT-T0101": "T0101",
    "MUFFIN-E0101": "E0101",
    "MUFFIN-C0101": "C0101"
  },
  "perspectives": [
    { "local_id": "MUFFIN-P0101", "id": "P0101", "label": "Options viability confirmed" },
    { "local_id": "CUPCAKE-P0101", "id": "P0102", "label": "Concentration risk mitigated" },
    { "local_id": "SCONE-P0101", "id": "P0103", "label": "Execution timeline concern" }
  ],
  "recommendations": [
    { "local_id": "DONUT-R0101", "id": "R0101", "label": "Amended collar structure" }
  ],
  "tensions": [
    { "local_id": "CROISSANT-T0101", "id": "T0101", "label": "Execution timing" }
  ],
  "evidence": [
    { "local_id": "MUFFIN-E0101", "id": "E0101", "label": "Historical options premium data" }
  ],
  "claims": [
    { "local_id": "MUFFIN-C0101", "id": "C0101", "label": "Income mandate resolved" }
  ],
  "tension_updates": [
    { "id": "T0001", "status": "addressed", "via": "R0101" },
    { "id": "T0002", "status": "resolved", "via": "P0102" }
  ]
}
```

All references stored with resolved global IDs. Note that local seq ≠ global seq:
- Local `MUFFIN-P0101` = Muffin's 1st perspective in round 1 (expert-local numbering)
- Global `P0103` = 3rd perspective registered in round 1 (dialogue-global numbering)

The `id_mapping` in the response tells the Judge exactly which local ID became which global ID.

The Judge receives:
- Log what was registered
- Reference new IDs in subsequent operations
- Build the scoreboard with correct global IDs

This replaces multiple individual calls with a single atomic operation.

**Export tool parameters:**

```json
{
  "dialogue_id": "nvidia-decision",
  "output_path": "/path/to/dialogues/nvidia-decision.json"
}
```

**Returns:**

```json
{
  "status": "success",
  "path": "/path/to/dialogues/nvidia-decision.json",
  "stats": {
    "rounds": 3,
    "experts": 12,
    "perspectives": 24,
    "recommendations": 8,
    "tensions": 12,
    "evidence": 6,
    "claims": 4,
    "totalAlignment": 423
  },
  "warnings": [
    { "type": "missing_score", "expert": "scone", "round": 2, "message": "Expert in panel but no score registered" }
  ]
}
```

### Error Handling

**MCP validates all data before database operations.** SQLite CHECK constraint errors are unhelpful ("CHECK constraint failed"), so the MCP layer must provide actionable feedback.

**Error response format:**

```json
{
  "status": "error",
  "error_code": "invalid_ref_target",
  "field": "ref_type",
  "value": "resolve",
  "constraint": "semantic",
  "message": "ref_type 'resolve' can only target Tensions (T), but target_type is 'P'",
  "context": {
    "source_id": "P0101",
    "target_id": "P0001",
    "target_type": "P"
  },
  "valid_options": ["T"],
  "suggestion": "Use 'support' or 'oppose' for Perspective targets, or change target to a Tension ID"
}
```

**Error codes and validation rules:**

| Error Code | Constraint | Trigger | Message Template |
|------------|------------|---------|------------------|
| `invalid_entity_type` | Type enum | `source_type` or `target_type` not in (P, R, T, E, C) | `{field} must be one of: P, R, T, E, C (got '{value}')` |
| `invalid_ref_type` | Ref enum | `ref_type` not in valid set | `ref_type must be one of: support, oppose, refine, address, resolve, reopen, question, depend (got '{value}')` |
| `type_id_mismatch` | Type consistency | `source_type` doesn't match `source_id` prefix | `{type}_type '{type_value}' does not match {type}_id '{id}' (expected prefix '{expected}')` |
| `invalid_ref_target` | Semantic | `resolve`/`reopen`/`address` targeting non-Tension | `ref_type '{ref}' can only target Tensions (T), but target_type is '{actual}'` |
| `refine_type_mismatch` | Semantic | `refine` with different source/target types | `ref_type 'refine' requires same source and target type (got {source}→{target})` |
| `target_not_found` | Referential | Referenced ID doesn't exist | `target_id '{id}' not found in dialogue '{dialogue_id}'` |
| `invalid_status_transition` | Lifecycle | Invalid state transition | `Cannot transition {entity} from '{from}' to '{to}' (valid transitions: {valid})` |

**Validation order:**

1. **Type enums** — Check `source_type`, `target_type`, `ref_type` are valid values
2. **Type consistency** — Check ID prefixes match declared types
3. **Referential integrity** — Check target IDs exist in the dialogue
4. **Semantic constraints** — Check relationship type is valid for target type
5. **Lifecycle rules** — Check status transitions are valid

**Partial success handling:**

For bulk operations (`blue_dialogue_round_register`), the MCP uses atomic transactions:
- **All-or-nothing**: If any item fails validation, the entire batch is rejected
- **Detailed errors**: Response includes validation errors for ALL failed items, not just the first

```json
{
  "status": "error",
  "error_code": "batch_validation_failed",
  "message": "3 items failed validation",
  "errors": [
    {
      "item_type": "reference",
      "source_id": "P0101",
      "error_code": "invalid_ref_target",
      "message": "ref_type 'resolve' can only target Tensions..."
    },
    {
      "item_type": "perspective",
      "local_id": "MUFFIN-P0102",
      "error_code": "type_id_mismatch",
      "message": "Perspective ID must start with 'P', got 'MUFFIN-P0102'"
    }
  ],
  "suggestion": "Fix all errors and resubmit the entire batch"
}
```

**Judge recovery pattern:**

When the Judge receives a validation error:
1. Parse the `error_code` and `suggestion`
2. Identify the problematic items
3. Correct the data based on `valid_options` or `suggestion`
4. Resubmit the entire batch (for bulk operations)

The structured error format ensures the Judge can programmatically understand and fix issues without human intervention.

### Agent Context Model

**MCP provides data; Judge builds prompts; Agents receive prompts directly.**

The Judge calls `blue_dialogue_round_context` once to get structured data for **all panel experts**:

```json
// Request
{
  "dialogue_id": "nvidia-decision",
  "round": 1
}

// Response
{
  "dialogue": {
    "id": "nvidia-decision",
    "title": "NVIDIA Investment Analysis",
    "question": "Should Acme Trust swap its NVAI position for NVDA shares?",
    "status": "open",
    "current_round": 1,
    "total_alignment": 117,
    "background": {
      "subject": "Acme Family Trust",
      "description": "$50M multi-generational family trust",
      "constraints": {
        "income_mandate": "4% annual distribution to beneficiaries",
        "risk_tolerance": "Moderate (fiduciary duty)",
        "time_horizon": "20+ years",
        "current_allocation": "60% equities, 30% fixed income, 10% alternatives"
      },
      "situation": "Trust holds $2.1M in NVAI (NVIDIA preferred, 3.2% yield). Proposal: swap NVAI for NVDA (common, 0% dividend). NVDA +180% YTD. Key tension: NVDA pays no dividend, conflicting with 4% income mandate."
    }
  },

  // Calibration (RFC 0054) — only present if calibrated: true
  "calibration": {
    "ethos_id": "ethos-nvidia-001",
    "domain": "Fiduciary Investment Analysis",
    "rules": [
      { "seq": 1, "type": "principle", "label": "Evidence must be citable", "priority": 100 },
      { "seq": 2, "type": "tenet", "label": "Fiduciary duty supersedes growth", "priority": 1000 },
      { "seq": 3, "type": "constraint", "label": "4% annual income required", "priority": 500 }
    ],
    "prompt_injection": "## Calibration: Fiduciary Investment Analysis\n\n..."
  },

  "prior_rounds": [
    {
      "round": 0,
      "score": 117,
      "expert_contributions": [
        {
          "expert": "muffin",
          "role": "Value Analyst",
          "perspectives": [
            { "id": "P0001", "label": "Income mandate mismatch", "status": "open", "content": "NVIDIA's zero dividend directly conflicts with the trust's 4% income requirement..." }
          ],
          "tensions_raised": ["T0001"],
          "recommendations": []
        },
        {
          "expert": "cupcake",
          "role": "Risk Manager",
          "perspectives": [
            { "id": "P0002", "label": "Concentration risk", "status": "open", "content": "Adding NVDA increases semiconductor exposure to 23% of portfolio..." }
          ],
          "tensions_raised": ["T0002"],
          "recommendations": []
        },
        {
          "expert": "donut",
          "role": "Options Strategist",
          "perspectives": [
            { "id": "P0003", "label": "Options overlay opportunity", "status": "open", "content": "A covered call strategy on NVDA could generate 18-34% annualized income..." }
          ],
          "tensions_raised": [],
          "recommendations": [
            { "id": "R0001", "label": "Income Collar Structure", "content": "Strike Selection Framework...", "parameters": { "covered_call_delta": "0.20-0.25" } }
          ]
        }
      ],
      "tensions": [
        { "id": "T0001", "label": "Growth vs income", "expert": "muffin", "status": "open", "description": "NVIDIA's zero dividend conflicts with 4% income mandate" },
        { "id": "T0002", "label": "Concentration risk", "expert": "cupcake", "status": "addressed", "description": "Semiconductor exposure would reach 23%" }
      ],
      "judge_synthesis": "11-1 split: majority concerns about income mandate..."
    }
  ],

  "active_tensions": [
    { "id": "T0001", "label": "Growth vs income", "status": "open" },
    { "id": "T0003", "label": "Volatility drag", "status": "open" }
  ],

  // Per-expert data keyed by slug
  "experts": {
    "muffin": {
      "slug": "muffin",
      "role": "Value Analyst",
      "tier": "Core",
      "source": "retained",
      "focus": "Intrinsic value, margin of safety",
      "description": "You evaluate investments through the lens of intrinsic value...",
      "your_score": 12,
      "round_context": "In round 0, you raised T0001 (income mandate mismatch) which remains open. Donut proposed an options overlay that may address your concern."
    },
    "cupcake": {
      "slug": "cupcake",
      "role": "Risk Manager",
      "tier": "Core",
      "source": "retained",
      "focus": "Downside scenarios, tail events",
      "description": "You identify and quantify risks...",
      "your_score": 8,
      "round_context": "Your T0002 (concentration risk) was addressed last round..."
    },
    "eclair": {
      "slug": "eclair",
      "role": "Tax Strategist",
      "tier": "Adjacent",
      "source": "pool",     // From initial pool, not previously active - Judge writes context brief
      "focus": "Tax implications, harvest strategies",
      "description": "You analyze tax consequences...",
      "your_score": 0,
      "round_context": null
    },
    "scone": {
      "slug": "scone",
      "role": "Supply Chain Analyst",
      "tier": "Wildcard",
      "source": "created",  // Invented by Judge - Judge writes context brief + mandate
      "focus": "Supply chain dependencies, geopolitical risk",
      "description": "You analyze supply chain vulnerabilities...",
      "your_score": 0,
      "round_context": null,
      "creation_reason": "Address T0003 supply chain concerns"
    }
  }
}
```

**One call returns context for entire panel.** Judge builds prompts in parallel from shared + expert-specific data.

**MCP provides structured data. Judge adds value through:**
- Emphasis and framing based on dialogue dynamics
- Custom `round_context` for each expert's situation
- Context briefs for fresh experts (constructed from structured data)

**For fresh experts** (pool or created):
- Judge writes a context brief from `prior_rounds` data, highlighting relevant prior discussion
- `prior_rounds` contains **full content** from all experts in all prior rounds (same as retained experts)
- The brief orients them; the full content lets them engage deeply
- `created` experts additionally receive a mandate explaining why they were invented

**Content availability guarantee:**
- All agents receive structured `perspectives`, `recommendations`, `tensions`, `evidence`, `claims` with full `content` field
- All IDs use global format (e.g., `P0001`, `R0001`, `T0001`) — no local ID confusion
- No content is hidden or summarized-only
- Fresh experts and retained experts see the same prior round data

*Note: Raw markdown responses are stored in `experts.raw_content` JSON for debugging but not included in agent context to avoid local/global ID confusion.*

### Prompt Assembly (Judge Responsibility)

The Judge fetches context in bulk and builds prompts in parallel:

```
1. FETCH (single call)
   └─ Judge calls blue_dialogue_round_context(dialogue_id, round)
   └─ MCP returns context for ALL panel experts

2. BUILD + WRITE (parallel for each expert)
   └─ Judge synthesizes markdown prompt from shared + expert data
   └─ Judge writes prompt-{expert}.md and context-{expert}.json

3. SPAWN (parallel - one message, multiple Task calls)
   └─ Judge spawns ALL agents with prompt + alignment-expert skill

4. RESPOND (parallel - agents run concurrently)
   └─ Each agent writes response-{expert}.md
```

**Why Judge builds prompts (not MCP):**
- Judge can emphasize specific tensions based on dialogue dynamics
- Judge can customize `round_context` per expert's situation
- Judge can frame fresh expert mandates appropriately
- MCP stays focused on data access, not LLM prompt engineering

**Parallelization benefits:**
- Single MCP call instead of N calls (reduces latency)
- Parallel file writes (no serialization)
- Parallel agent spawning (all in one message)
- Agents run concurrently (no first-mover advantage)

**Filesystem artifacts (for human debugging):**

| File | Written by | Purpose |
|------|------------|---------|
| `prompt-{expert}.md` | Judge | Exact markdown prompt agent received |
| `context-{expert}.json` | Judge | Structured JSON data used to build prompt |
| `response-{expert}.md` | Agent | Agent's deliberation response |

**Prompt format:**

```markdown
# Dialogue: NVIDIA Investment Analysis
**Question:** Should Acme Trust swap its NVAI position for NVDA shares?
**Round:** 1 of ? | **Status:** open | **Total ALIGNMENT:** 117

---

## Background

**Acme Family Trust** is a $50M multi-generational family trust.

| Constraint | Requirement |
|------------|-------------|
| Income mandate | 4% annual distribution to beneficiaries |
| Risk tolerance | Moderate (fiduciary duty) |
| Time horizon | 20+ years |
| Current allocation | 60% equities, 30% fixed income, 10% alternatives |

**Current situation:**
- Trust holds $2.1M in NVAI (NVIDIA preferred, 3.2% yield)
- Proposal: Swap NVAI → NVDA (common shares, 0% dividend)
- NVDA has appreciated 180% YTD; NVAI underperformed
- Key tension: NVDA pays no dividend, conflicting with 4% income mandate

---

## Your Role

**Muffin** 🧁 | Value Analyst | Core
Focus: Intrinsic value, margin of safety
Your score: 12 | Source: retained

You evaluate investments through the lens of intrinsic value, seeking companies
trading below fair value with adequate margin of safety. You are skeptical of
momentum-driven narratives and prioritize cash flow analysis, balance sheet
strength, and sustainable competitive advantages.

### Your Task This Round

In round 0, you raised T0001 (income mandate mismatch) which remains open. Donut
proposed an options overlay that may address your concern. Your task this round:
evaluate whether the options strategy adequately resolves the income gap, or
articulate why it falls short.

---

## Prior Rounds

### Round 0 — Opening Arguments (Score: 117)

#### Muffin (You) — Value Analyst
[P0001: Income mandate mismatch] (muffin)
NVIDIA's zero dividend directly conflicts with the trust's 4% income requirement...

[TENSION T0001: Growth vs income]
The fundamental tension between growth exposure and income mandate.

---

#### Cupcake — Risk Manager
[P0002: Concentration risk] (cupcake)
Adding NVDA increases semiconductor exposure to 23% of portfolio...

[TENSION T0002: Concentration risk]
Portfolio concentration in semiconductors exceeds policy limits.

---

#### Donut — Options Strategist
[P0003: Options overlay opportunity] (donut)
A covered call strategy on NVDA could generate 18-34% annualized income...

[R0001: Income Collar Structure] (donut)
Strike Selection Framework:
| Parameter | Value | Rationale |
|-----------|-------|-----------|
| Covered call delta | 0.20-0.25 | Balance premium vs upside |
| Protective put delta | -0.15 | Tail risk protection |
| DTE | 30-45 | Optimal theta decay |

---

### Judge Synthesis — Round 0
11-1 split: majority concerns about income mandate, but Donut's options overlay
opens a potential path forward. Key tensions T0001 and T0002 require resolution.

---

## Active Tensions

| ID | Description | Origin | Status | Your Involvement |
|----|-------------|--------|--------|------------------|
| T0001 | Growth vs income mandate | Muffin | open | originator |
| T0002 | Concentration risk | Cupcake | addressed | — |
| T0003 | Volatility drag on returns | Scone | open | — |

---

## Instructions

You are Muffin 🧁, a Value Analyst participating in round 1 of this ALIGNMENT dialogue.

Your contribution is scored on PRECISION, not volume. One sharp insight beats ten paragraphs.

Structure your response using the markers from your skill (P, R, T, E, C for perspectives, recommendations, tensions, evidence, claims; plus cross-references and moves). Use your expert slug in local IDs: `MUFFIN-P0101`, `MUFFIN-R0101`, `MUFFIN-T0101`, etc.

Focus on: What has changed since round 0? Which tensions can you help resolve?
```

### Alignment Expert Skill

Agents are spawned with the `alignment-expert` skill, which contains **static** marker syntax reference. This avoids repeating ~800 tokens of marker documentation in every prompt.

**Skill file:** `~/.claude/skills/alignment-expert/SKILL.md`

```markdown
# Alignment Expert

You are an expert participating in an ALIGNMENT dialogue. Structure your
response using these markers.

## Local ID Format

Use your expert slug (UPPERCASE) with type prefix and 4-digit round+seq:
- `{EXPERT}-P{round:02d}{seq:02d}` — Perspective (e.g., MUFFIN-P0101)
- `{EXPERT}-R{round:02d}{seq:02d}` — Recommendation (e.g., MUFFIN-R0101)
- `{EXPERT}-T{round:02d}{seq:02d}` — Tension (e.g., MUFFIN-T0101)
- `{EXPERT}-E{round:02d}{seq:02d}` — Evidence (e.g., MUFFIN-E0101)
- `{EXPERT}-C{round:02d}{seq:02d}` — Claim (e.g., MUFFIN-C0101)

## First-Class Entities

| Marker | Purpose |
|--------|---------|
| `[{local_id}: label]` | Type encoded in ID prefix (P, R, T, E, C) |

Examples:
- `[MUFFIN-P0101: Income mandate mismatch]` — Perspective
- `[DONUT-R0101: Options collar structure]` — Recommendation
- `[MUFFIN-T0101: Growth vs income]` — Tension
- `[MUFFIN-E0101: Historical IV data]` — Evidence
- `[MUFFIN-C0101: Income gap bridgeable]` — Claim

## Cross-References

Link to prior items (global IDs) or same-round items (local IDs):

| Marker | Purpose |
|--------|---------|
| `[RE:SUPPORT {id}]` | Endorse referenced item |
| `[RE:OPPOSE {id}]` | Challenge referenced item |
| `[RE:REFINE {id}]` | Build on and improve (same type only) |
| `[RE:ADDRESS {id}]` | Propose solution to tension |
| `[RE:RESOLVE {id}]` | Claim tension is fully resolved |
| `[RE:REOPEN {id}]` | Argue resolved tension needs revisiting |
| `[RE:QUESTION {id}]` | Ask for clarification |
| `[RE:DEPEND {id}]` | This item depends on referenced item |

**Constraints:**
- `RE:RESOLVE`, `RE:REOPEN`, `RE:ADDRESS` — must target Tensions (T)
- `RE:REFINE` — must target same entity type (P→P, R→R, etc.)

## Dialogue Moves

| Marker | Purpose |
|--------|---------|
| `[MOVE:DEFEND {id}]` | Strengthen case for item |
| `[MOVE:CHALLENGE {id}]` | Question assumptions |
| `[MOVE:BRIDGE {id1} {id2}]` | Synthesize into common ground |
| `[MOVE:REQUEST {topic}]` | Ask panel for input |
| `[MOVE:CONCEDE {id}]` | Withdraw position in favor of item |
| `[MOVE:CONVERGE]` | Signal readiness to conclude |

## Verdicts

| Marker | Purpose |
|--------|---------|
| `[DISSENT]` | Formal objection with reasoning |
| `[MINORITY VERDICT: label]` | Alternative recommendation from coalition |

## Output Rules

1. Write response to: `{output_dir}/round-{N}/response-{expert_slug}.md`
2. Return structured summary to Judge (perspectives, recommendations, tensions, evidence, claims, refs)
3. One sharp insight beats ten paragraphs — PRECISION over volume
```

**Judge spawns agents with:**

```python
spawn_agent(
    skill="alignment-expert",  # Static marker syntax
    prompt=full_markdown_prompt  # Dynamic context (Judge-built)
)
```

**Separation of concerns:**

| Content | Source | Rationale |
|---------|--------|-----------|
| Marker syntax | Skill | Static, same for all agents, ~800 tokens |
| Dialogue background | Prompt | Dynamic, dialogue-specific |
| Expert role/mandate | Prompt | Dynamic, agent-specific |
| Prior rounds | Prompt | Dynamic, round-specific |
| Active tensions | Prompt | Dynamic, changes each round |
| Instructions | Prompt | Dynamic, may vary by expert source |

**Why Judge passes prompt directly (not file path):**
- Simpler — no file read step for agent
- Fewer failure modes — no file access issues
- Prompt is already in Judge's memory
- Filesystem write is for human debugging only

### Dynamic Expert Creation

The Judge can **create new experts at any point** before a round to address emerging needs:

**MCP tool:** `blue_dialogue_expert_create`

```json
{
  "dialogue_id": "nvidia-decision",
  "expert_slug": "palmier",
  "role": "Geopolitical Risk Analyst",
  "description": "You analyze investments through the lens of geopolitical risk, focusing on supply chain vulnerabilities, regulatory exposure, and country-specific risks. You are particularly attentive to concentration risk in politically sensitive regions.",
  "focus": "Taiwan semiconductor concentration, export controls",
  "tier": "Adjacent",
  "reason": "T0003 (supply chain concentration) requires specialized geopolitical expertise not present in current panel"
}
```

**When to create experts:**
- Existing panel lacks expertise to resolve a specific tension
- New deliberation focus emerges that needs dedicated attention
- Wildcard injection to challenge emerging consensus
- Domain shift mid-dialogue (e.g., legal question surfaces)

**What happens:**
1. Judge calls `blue_dialogue_expert_create` before the round
2. MCP inserts expert into `experts` table with `source: "created"`
3. Expert is included in next `blue_dialogue_evolve_panel` call
4. Judge constructs context brief from `blue_dialogue_round_context` structured data

**Created experts receive (assembled by Judge):**
- Full `prior_rounds` content (same as retained experts)
- Judge-written context brief summarizing relevant discussion and why they were brought in
- `round_context` focused on their specific mandate

**Example context brief for created expert:**

```markdown
## Context Brief (You are joining in Round 2)

You were brought in to address **T0003: Supply chain concentration risk**.

---

### The Dialogue Question

**Should Acme Family Trust swap its NVAI position for NVDA shares?**

### Background: Acme Family Trust

Acme Family Trust is a $50M multi-generational family trust with the following
constraints:

| Constraint | Requirement |
|------------|-------------|
| **Income mandate** | 4% annual distribution to beneficiaries |
| **Risk tolerance** | Moderate (fiduciary duty to preserve capital) |
| **Time horizon** | 20+ years (multi-generational) |
| **Current allocation** | 60% equities, 30% fixed income, 10% alternatives |

**Current situation:**
- Trust holds $2.1M in NVAI (NVIDIA preferred shares, 3.2% yield)
- Proposal: Swap NVAI for NVDA (common shares, 0% dividend)
- NVDA has appreciated 180% YTD; NVAI has underperformed
- Trustee believes NVDA growth potential outweighs income loss

**Key tension:** NVDA pays no dividend, conflicting with 4% income mandate.

---

### Why You're Here

After two rounds of deliberation, the income mandate concerns (T0001) have been
resolved via an options overlay strategy. However, a critical tension remains
unaddressed: **geographic concentration risk in semiconductor supply chain**.

No current panelist has geopolitical risk expertise, so you were created to
provide this specialized perspective.

### Your Mandate

1. Evaluate the geopolitical risk of Taiwan semiconductor concentration
2. Quantify probability and impact scenarios for supply disruption
3. Propose risk mitigation strategies if viable
4. If risks are unacceptable, strengthen the case for rejection

---

### Key Context: The Tension You're Addressing

**T0003: Supply chain concentration risk** (raised by Cupcake, Round 0)
> "NVIDIA's 87% dependency on TSMC Taiwan fabrication represents unhedgeable
> tail risk. A Taiwan Strait crisis would eliminate access to advanced chips
> with no alternative supplier capable of 3nm production."

### Relevant Prior Perspectives

**P0003** (Cupcake, Risk Manager, Round 0):
> "Taiwan exposure represents unhedgeable tail risk. Unlike financial risks
> that can be managed through derivatives, geopolitical supply disruption has
> no market hedge. The 87% TSMC concentration means a single point of failure
> for NVIDIA's entire product line. Historical precedent: the 2021 chip
> shortage caused 18-month delivery delays even without military conflict."

**P0005** (Scone, Supply Chain Analyst, Round 1):
> "TSMC has no viable alternative for 3nm production. Intel Foundry Services
> won't reach parity until 2027 at earliest. Samsung's 3nm yields remain
> below 60%. NVIDIA cannot diversify its fab dependency in the investment
> horizon we're considering. The concentration is structural, not strategic."

**P0008** (Donut, Options Strategist, Round 1):
> "Geopolitical risk cannot be hedged with options. While we can manage
> volatility and income through derivatives, there is no instrument that
> protects against a binary supply disruption event. This is outside my
> domain—we need specialized geopolitical analysis."

---

### Dialogue Progress

- **Round 0 (Score: 117):** Panel identified income mandate conflict and
  concentration risks. 11-1 against full position.
- **Round 1 (Score: 45):** Options overlay resolved income concerns. T0001
  addressed. T0003 flagged as requiring specialized expertise.
- **Current ALIGNMENT:** 162 (velocity decreasing, approaching convergence
  pending T0003 resolution)

### What the Panel Needs From You

The panel is close to convergence on a conditional approval, but T0003 blocks
final consensus. Your analysis will determine whether:
- The geopolitical risk is acceptable with conditions → conditional approval
- The risk is unacceptable → strengthen rejection case
- The risk can be mitigated → propose specific measures
```

**Context brief requirements (Judge responsibility):**

The context brief the Judge writes for fresh experts (pool or created) MUST include:

1. **The dialogue question** — What is being decided?
2. **Foundational context** — Background, constraints, current situation (everything an expert needs to understand the problem domain)
3. **Why they're here** — What gap they fill or tension they address
4. **Their mandate** — Specific responsibilities and expected outputs
5. **Relevant prior work** — Key perspectives, recommendations, tensions, evidence, claims related to their mandate
6. **Dialogue progress** — Round summaries, current ALIGNMENT, velocity

Fresh experts must be **fully self-sufficient** after reading their context. They should never need to ask "what is this dialogue about?" or "what are the constraints?"

*Note: Fresh experts (pool or created) also receive the full `prior_rounds` data (same as retained experts), so they can review all expert contributions in detail. The context brief orients them to the dialogue and highlights the most relevant prior work.*

**Expert sources in panel evolution:**

| Source | Meaning | Context |
|--------|---------|---------|
| `retained` | Continuing from prior round | Full history, their contributions highlighted |
| `pool` | Drawn from initial expert pool (not previously active) | Full history + Judge-written brief |
| `created` | Invented by Judge for this dialogue (not in pool) | Full history + Judge-written brief + mandate |

### Judge Workflow (for skill documentation)

**Round execution (maximally parallelized):**

```
0. EVOLVE PANEL (Judge discretion)
   └─ Judge reviews prior round results, open tensions, dialogue progress
   └─ Judge decides panel composition for this round:
      - Retain high-performing experts
      - Draw from pool to address gaps
      - Create new experts for specialized needs
   └─ Judge calls blue_dialogue_evolve_panel(dialogue_id, round, panel)
      → MCP records panel composition with source for each expert

1. FETCH CONTEXT (single bulk call)
   └─ Judge calls blue_dialogue_round_context(dialogue_id, round)
      → MCP returns context for ALL panel experts in one response
      → Shared data: dialogue, background, prior_rounds, active_tensions
      → Per-expert data: role, focus, source, round_context

2. BUILD PROMPTS + WRITE FILES (parallel)
   └─ For fresh experts (pool or created): Judge writes context brief from structured data
   └─ For each expert IN PARALLEL:
      └─ Judge synthesizes markdown prompt from shared + expert data
      └─ Judge writes prompt-{expert}.md (parallel file writes)
      └─ Judge writes context-{expert}.json (parallel file writes)

3. SPAWN AGENTS (parallel)
   └─ Judge spawns ALL agents in ONE message with multiple Task tool calls:
      - skill: alignment-expert (static marker syntax)
      - prompt: full markdown content (from step 2)
   └─ Agents deliberate using prompt + skill
   └─ Agents write responses with LOCAL IDs: [MUFFIN-P0101]
   └─ Each agent writes to: {output_dir}/round-{N}/response-{expert_slug}.md
   └─ Each agent returns summary to Judge

4. COLLECT AGENT OUTPUTS
   └─ Judge receives agent return values (summaries of what each contributed)
   └─ Judge reads full responses from {output_dir}/round-{N}/response-*.md
   └─ Judge reviews all contributions, identifies:
      - New perspectives (with local IDs like MUFFIN-P0101)
      - New proposals (with local IDs like DONUT-R0101)
      - New tensions (with local IDs like CUPCAKE-T0101)
      - Tension updates (addressed, resolved)
      - Cross-references between experts

5. SCORE AND REGISTER
   └─ Judge scores each expert's contribution (ALIGNMENT dimensions)
   └─ Judge synthesizes similar contributions (multiple experts → one record)
   └─ Judge calls blue_dialogue_round_register({
        round, score, expert_scores,
        perspectives, recommendations, tensions, evidence, claims,
        tension_updates
      })
      → MCP assigns global IDs (P0101, R0101, T0101)
      → Returns ID mapping for Judge's records

6. CHECK CONVERGENCE
   └─ If converging: blue_dialogue_verdict_register(...) after step 5
   └─ If continuing: goto step 0 for next round (panel evolution)
```

**Agent output format:**

Each agent writes a markdown file with structured markers:
```markdown
# Muffin - Value Analyst (Round 1)

[MUFFIN-P0101: Options viability confirmed]
The 30-delta covered call strategy can generate 18-34% annualized income,
effectively bridging the income mandate gap...

[RE: DONUT-R0001]
The collar structure addresses my T0001 concern. I support adoption with
the 45 DTE modification.

[MUFFIN-T0102: Execution timing risk]
Post-refinancing window creates a 60-90 day constraint that may conflict
with optimal entry points...
```

**Agent return value:**

Agents return a structured summary to the Judge:
```json
{
  "expert_slug": "muffin",
  "round": 1,
  "response_path": "/tmp/blue-dialogue/nvidia-decision/round-1/response-muffin.md",
  "summary": {
    "perspectives": ["MUFFIN-P0101"],
    "recommendations": [],
    "tensions_raised": ["MUFFIN-T0101"],
    "evidence": ["MUFFIN-E0101"],
    "claims": ["MUFFIN-C0101"],
    "references": [
      { "type": "refine", "from": "MUFFIN-P0101", "target": "P0001" },
      { "type": "support", "from": "MUFFIN-P0101", "target": "R0001" },
      { "type": "address", "from": "MUFFIN-P0101", "target": "T0001" },
      { "type": "support", "from": "MUFFIN-E0101", "target": "MUFFIN-P0101" },
      { "type": "depend", "from": "MUFFIN-C0101", "target": "MUFFIN-P0101" }
    ],
    "moves": [
      { "type": "bridge", "targets": ["P0003", "R0001"] }
    ]
  }
}
```

**Why Judge builds prompts (not MCP or agents):**
- Judge can customize emphasis based on dialogue dynamics
- Judge controls framing for fresh vs retained experts
- Judge writes context_brief with specific mandates for created experts
- MCP stays focused on data access, not prompt engineering

**Key points for alignment-play skill:**
- Judge fetches data via `blue_dialogue_round_context`, builds prompts
- Judge writes prompts to filesystem for debugging
- Judge spawns agents with full prompt + `alignment-expert` skill
- Agents write local IDs — Judge maps to global IDs during registration
- Use `blue_dialogue_round_register` for bulk operations (faster)

### Data Registration Model

**All dialogue data is registered via MCP tools as the dialogue progresses.** The Judge registers data after each round:

```
Round 0 completes:
  → Judge scores responses
  → Judge calls blue_dialogue_round_register with all round data:
    - perspectives, recommendations, tensions, evidence, claims
    - cross-references (refs)
    - tension_updates
    - expert_scores

Round N completes (convergence):
  → Judge calls blue_dialogue_round_register (same as every round)
  → Judge calls blue_dialogue_verdict_register for majority verdict
  → Judge identifies dissenters from final round contributions
  → Judge calls blue_dialogue_verdict_register for each minority verdict (on behalf of dissenting experts)
```

**Benefits:**
- Export is a simple DB query, no file parsing
- Data is queryable in real-time during dialogue
- Single source of truth (database, not scattered files)
- Files (`.md`) become human-readable artifacts, not data sources

### Export Tooling: `blue_dialogue_export`

The MCP tool queries the database and generates a single JSON file:

```
blue_dialogue_export(dialogue_id="nvidia-decision", output_path="/path/to/nvidia-decision.json")
  → Single file with all dialogue data
```

#### Data Sources (all from SQLite)

| Table | Export Section |
|-------|----------------|
| `dialogues` | Root metadata, status, alignment total |
| `experts` | `experts[]` with `scores` and `raw_content` JSON (per-round) |
| `expert_pool` | `expert_pool` (original pool definition) |
| `rounds` | `rounds[]` metadata |
| `perspectives` | `perspectives[]` with events |
| `proposals` | `proposals[]` with events |
| `tensions` | `tensions[]` with events |
| `evidence` | `evidence[]` with events |
| `claims` | `claims[]` with events |
| `refs` | Embedded in each entity's `references[]` array |
| `moves` | `moves[]` (dialogue moves: defend, challenge, bridge, etc.) |
| `tension_events` | Embedded in tension `events[]` |
| `verdicts` | `verdicts[]` |

#### Output: Single `dialogue.json`

```json
{
  "id": "nvidia-decision",
  "title": "NVIDIA Investment Decision",
  "question": "Should Acme Trust add NVIDIA?",
  "date": "2026-02-02",
  "status": "converged",
  "totalRounds": 3,
  "totalAlignment": 423,

  "expert_pool": {
    "domain": "Investment Analysis",
    "experts": [
      { "role": "Value Analyst", "tier": "Core", "relevance": 0.95 },
      { "role": "Risk Manager", "tier": "Core", "relevance": 0.90 }
    ]
  },

  "experts": [
    {
      "slug": "muffin",
      "role": "Value Analyst",
      "tier": "Core",
      "source": "pool",
      "scores": { "0": 12, "1": 8, "2": 15 },
      "total": 35,
      "color": "#3B82F6"
    },
    {
      "slug": "palmier",
      "role": "Geopolitical Risk Analyst",
      "tier": "Adjacent",
      "source": "created",
      "creationReason": "T0003 requires geopolitical expertise",
      "scores": { "2": 14 },
      "total": 14,
      "color": "#10B981"
    }
  ],

  "rounds": [
    {
      "round": 0,
      "title": "Opening Arguments",
      "score": 117,
      "summary": "11-1 split on full swap vs conditional support",
      "experts": {
        "muffin": {
          "score": 12,
          "raw": "[MUFFIN-P0001: Income mandate mismatch]\nNVIDIA's zero dividend...",
          "mapping": { "MUFFIN-P0001": "P0001", "MUFFIN-T0001": "T0001" }
        },
        "cupcake": {
          "score": 10,
          "raw": "[CUPCAKE-P0001: Concentration risk]\n...",
          "mapping": { "CUPCAKE-P0001": "P0002" }
        }
      }
    },
    {
      "round": 1,
      "title": "Refinement",
      "score": 45,
      "summary": "Options overlay gains traction, T0001 addressed",
      "experts": {
        "muffin": {
          "score": 8,
          "raw": "[MUFFIN-P0101: Options viability confirmed]\n...",
          "mapping": { "MUFFIN-P0101": "P0101" }
        }
      }
    }
  ],

  "perspectives": [
    {
      "id": "P0001",
      "label": "Income mandate mismatch",
      "content": "NVIDIA's zero dividend directly conflicts with the trust's 4% income requirement...",
      "contributors": ["muffin"],
      "round": 0,
      "status": "refined",
      "references": [],
      "events": [
        { "type": "created", "round": 0, "by": ["muffin"] },
        { "type": "refined", "round": 1, "by": ["muffin"], "result": "P0101" }
      ]
    },
    {
      "id": "P0101",
      "label": "Options viability confirmed",
      "content": "The 30-delta covered call strategy can generate 18-34% annualized income...",
      "contributors": ["muffin"],
      "round": 1,
      "status": "open",
      "references": [
        { "type": "refine", "target": "P0001" },
        { "type": "support", "target": "R0001" },
        { "type": "address", "target": "T0001" }
      ],
      "events": [
        { "type": "created", "round": 1, "by": ["muffin"] }
      ]
    }
  ],

  "recommendations": [
    {
      "id": "R0001",
      "label": "Income Collar Structure",
      "content": "Strike Selection Framework for synthetic income generation...",
      "contributors": ["donut"],
      "round": 0,
      "status": "adopted",
      "parameters": {
        "covered_call_delta": "0.20-0.25",
        "protective_put_delta": "-0.15",
        "dte": "30-45"
      },
      "references": [
        { "type": "address", "target": "T0001" },
        { "type": "depend", "target": "P0001" }
      ],
      "adoptedInVerdict": "final",
      "events": [
        { "type": "created", "round": 0, "by": ["donut"] },
        { "type": "adopted", "round": 2, "by": ["judge"], "reference": "final" }
      ]
    }
  ],

  "tensions": [
    {
      "id": "T0001",
      "label": "Growth vs income obligation",
      "description": "NVIDIA's zero dividend conflicts with trust's 4% income requirement",
      "contributors": ["muffin"],
      "round": 0,
      "status": "resolved",
      "references": [
        { "type": "depend", "target": "P0001" }
      ],
      "events": [
        { "type": "created", "round": 0, "by": ["muffin"] },
        { "type": "addressed", "round": 1, "by": ["donut"], "reference": "R0001" },
        { "type": "resolved", "round": 2, "by": ["muffin"], "reference": "P0101" }
      ]
    }
  ],

  "evidence": [
    {
      "id": "E0101",
      "label": "Historical options premium data",
      "content": "NVDA 30-day ATM IV averaged 45% over past 24 months. 30-delta calls yielded 2.1-2.8% monthly premium. Premium remained viable during Q4 2022 drawdown.",
      "contributors": ["muffin"],
      "round": 1,
      "status": "confirmed",
      "references": [
        { "type": "support", "target": "P0101" }
      ],
      "events": [
        { "type": "cited", "round": 1, "by": ["muffin"] },
        { "type": "confirmed", "round": 2, "by": ["donut"], "reference": "R0001" }
      ]
    }
  ],

  "claims": [
    {
      "id": "C0101",
      "label": "Income mandate resolved",
      "content": "The income mandate objection is resolved via options overlay. Remaining concerns are execution timing and concentration—both manageable with phased approach.",
      "contributors": ["muffin"],
      "round": 1,
      "status": "adopted",
      "references": [
        { "type": "depend", "target": "P0101" },
        { "type": "depend", "target": "E0101" }
      ],
      "events": [
        { "type": "asserted", "round": 1, "by": ["muffin"] },
        { "type": "supported", "round": 2, "by": ["donut", "cupcake"] },
        { "type": "adopted", "round": 2, "by": ["judge"], "reference": "final" }
      ]
    }
  ],

  "moves": [
    {
      "expert": "muffin",
      "round": 1,
      "type": "bridge",
      "targets": ["P0003", "R0001"],
      "context": "Reconciling concentration concern with collar proposal via phased entry"
    },
    {
      "expert": "donut",
      "round": 1,
      "type": "defend",
      "targets": ["R0001"],
      "context": "NVDA options liquidity supports execution viability"
    },
    {
      "expert": "cupcake",
      "round": 2,
      "type": "concede",
      "targets": ["P0003"],
      "context": "Phased entry adequately addresses concentration concern"
    },
    {
      "expert": "muffin",
      "round": 2,
      "type": "converge",
      "targets": [],
      "context": "Ready to conclude with conditional approval"
    }
  ],

  "verdicts": [
    {
      "id": "final",
      "type": "final",
      "round": 2,
      "author": null,
      "recommendation": "REJECT full swap. APPROVE conditional partial trim.",
      "description": "The panel unanimously rejected a full NVAI-to-NVDA swap...",
      "conditions": [
        "Execute 60-90 days post-refinancing",
        "Implement 30-delta covered calls at 45 DTE"
      ],
      "tensionsResolved": ["T0001", "T0002"],
      "tensionsAccepted": ["T0006"],
      "recommendationsAdopted": ["R0001"],
      "keyEvidence": ["E0101"],
      "keyClaims": ["C0101"],
      "vote": "12-0",
      "confidence": "unanimous"
    }
  ]
}
```

**Key sections:**

| Section | Contents |
|---------|----------|
| `expert_pool` | Original pool definition (for reference) |
| `experts[]` | Participating experts with per-round scores |
| `rounds[]` | Round metadata + raw expert content with local→global ID mapping |
| `perspectives[]` | Positions and arguments with `references[]` and events |
| `proposals[]` | Actionable recommendations with parameters, `references[]`, and events |
| `tensions[]` | Conflicts and risks with `references[]`, lifecycle, and events |
| `evidence[]` | Data and precedents with `references[]` and events |
| `claims[]` | Quotable position statements with `references[]` and events |
| `moves[]` | Dialogue moves (defend, challenge, bridge, concede, converge) |
| `verdicts[]` | All verdicts (interim, final, minority, dissent) |

#### Perspective Status Tracking

The export tracks perspective lifecycle across rounds:

| Status | Meaning |
|--------|---------|
| `open` | No engagement yet |
| `refined` | Expert evolved their own perspective |
| `conceded` | Expert withdrew after peer challenge |
| `resolved` | Tension addressed, perspective incorporated |

#### Verdict Structure

Dialogues support **multiple verdicts** to capture interim decisions, final conclusions, and minority positions:

```json
{
  "verdicts": [
    {
      "id": "string",                    // "final", "V01", "minority-esg"
      "type": "final",                   // interim | final | minority | dissent
      "round": 3,                        // Round when issued
      "author": "string | null",         // Expert slug, or null for Judge
      "recommendation": "string",        // One-line decision
      "description": "string",           // 2-3 sentence reasoning
      "conditions": ["string"],          // Required conditions for approval
      "tensions_resolved": ["T0001"],      // Tensions addressed by this verdict
      "tensions_accepted": ["T0006"],      // Tensions acknowledged but not blocking
      "recommendations_adopted": ["R0001"],  // Recommendations incorporated
      "supporting_experts": ["churro"],  // For minority/dissent types
      "vote": "11-1",                    // Vote tally
      "confidence": "strong"             // unanimous | strong | split | contested
    }
  ]
}
```

**Verdict types:**

| Type | When Used | Author |
|------|-----------|--------|
| `interim` | Mid-dialogue checkpoint, steering decision | Judge |
| `final` | Authoritative conclusion at convergence | Judge |
| `minority` | Structured dissent from expert subset | Lead dissenting expert |
| `dissent` | Single expert's formal objection | Dissenting expert |

**Registered via MCP** using `blue_dialogue_verdict_register`:
- Judge registers `interim` and `final` verdicts
- Experts can signal dissent to the Judge, who registers `minority` or `dissent` verdicts on their behalf
- All verdicts are immutable once registered (audit trail)

**Populated from:**
- `[VERDICT]` markers in round summaries (Judge)
- `[DISSENT]` markers in expert responses
- `[MINORITY VERDICT]` markers from expert coalitions
- Resolved/accepted tension status at time of verdict

#### Global ID Assignment

Global IDs are assigned at **registration time**, not export time:

1. Judge calls `blue_dialogue_round_register` with all round data
2. MCP server assigns global `seq` for each entity within `(dialogue_id, round)`
3. Display ID derived: `P{round:02d}{seq:02d}`, `R{round:02d}{seq:02d}`, etc.
4. Export queries database with IDs already assigned

**No renumbering needed** - the database is the source of truth for all IDs.

#### Validation & Warnings

The export validates database consistency:
- Missing expert scores (expert in panel but no score for round)
- Unresolved tensions at convergence
- Orphaned perspectives (no matching expert registration)
- Verdict without required fields

```
⚠️  Warnings:
   missing_score: scone, round 2
      Expert was in panel but has no score registered
   unresolved_tension: T0006
      Dialogue converged with open tension (accepted)
   verdict_incomplete: final
      Missing tensions_resolved field
```

### Two-Phase ID Assignment

**Phase 1: Agents write with namespaced local IDs**

Agents use expert-prefixed local IDs in their output:
```markdown
[MUFFIN-P0001: Income mandate mismatch]
[DONUT-R0001: Options collar structure]
[MUFFIN-T0001: Growth vs income]
```

These are local to the agent's response. The slug prefix keeps them unique, but sequence numbers overlap across experts (e.g., both MUFFIN-P0101 and CUPCAKE-P0101 exist).

**Phase 2: Judge registers with global IDs**

When Judge registers content, the MCP assigns a **global ID**:
- `P0001`, `P0002`, `P0003`... (perspectives, globally sequential per round)
- `R0001`, `R0002`... (proposals, globally sequential per round)
- `T0001`, `T0002`... (tensions, globally sequential per round)
- `E0001`, `E0002`... (evidence, globally sequential per round)
- `C0001`, `C0002`... (claims, globally sequential per round)

The original namespaced ID is discarded. Expert attribution is stored in the record, not encoded in the ID.

**Downstream: Global IDs only**

All references after registration use global IDs:
- Cross-references: `[RE:SUPPORT E0001]`, `[RE:OPPOSE C0003]`
- Tension links: `references: [{"type": "address", "target": "T0001"}]`
- Verdicts: `recommendationsAdopted: ["R0001"]`, `keyEvidence: ["E0001"]`

### Display ID Formulas

All IDs use `{round:02d}{seq:02d}` format (4 digits):

| Entity | Formula | Examples |
|--------|---------|----------|
| Perspective | `P{round:02d}{seq:02d}` | P0001, P0102, P0215 |
| Recommendation | `R{round:02d}{seq:02d}` | R0001, R0102 |
| Tension | `T{round:02d}{seq:02d}` | T0001, T0102 |
| Evidence | `E{round:02d}{seq:02d}` | E0001, E0103 |
| Claim | `C{round:02d}{seq:02d}` | C0001, C0205 |

The format encodes round implicitly:
- `P0001` = round 0, seq 1
- `P0102` = round 1, seq 2
- `P0215` = round 2, seq 15

This gives:
- 99 rounds max (00-99)
- 99 items per entity type per round (01-99)
- Human-readable IDs with expert attribution in data, not ID

### Expert Content Markers

Experts use these markers in their responses for structured extraction.

#### First-Class Entities (Global IDs assigned by MCP)

| Marker | Local ID Example | Description |
|--------|------------------|-------------|
| `[{local_id}: label]` | `MUFFIN-P0101` | Perspective: Position or argument |
| `[{local_id}: label]` | `MUFFIN-R0101` | Recommendation: Actionable proposal |
| `[{local_id}: label]` | `MUFFIN-T0101` | Tension: Conflict, risk, or unresolved issue |
| `[{local_id}: label]` | `MUFFIN-E0101` | Evidence: Data, precedent, or fact |
| `[{local_id}: label]` | `MUFFIN-C0101` | Claim: Quotable position statement |

Type is encoded in the ID prefix: `P` (perspective), `R` (recommendation), `T` (tension), `E` (evidence), `C` (claim).

#### Status Lifecycles

| Entity | Statuses |
|--------|----------|
| Perspective | `open` → `refined` / `conceded` / `merged` |
| Recommendation | `proposed` → `amended` → `adopted` / `rejected` |
| Tension | `open` → `addressed` → `resolved` / `reopened` |
| Evidence | `cited` → `challenged` → `confirmed` / `refuted` |
| Claim | `asserted` → `supported` / `opposed` → `adopted` / `withdrawn` |

#### Cross-References

The `[RE: ...]` marker creates typed relationships between contributions:

| Syntax | Meaning | Example |
|--------|---------|---------|
| `[RE:SUPPORT {id}]` | Endorses the referenced item | `[RE:SUPPORT R0001]` |
| `[RE:OPPOSE {id}]` | Challenges or disagrees with item | `[RE:OPPOSE P0003]` |
| `[RE:REFINE {id}]` | Builds on and improves item | `[RE:REFINE P0001]` |
| `[RE:ADDRESS {id}]` | Proposes solution to tension | `[RE:ADDRESS T0001]` |
| `[RE:RESOLVE {id}]` | Claims tension is fully resolved | `[RE:RESOLVE T0001]` |
| `[RE:REOPEN {id}]` | Argues resolved tension needs revisiting | `[RE:REOPEN T0002]` |
| `[RE:QUESTION {id}]` | Asks for clarification | `[RE:QUESTION R0001]` |
| `[RE:DEPEND {id}]` | This item depends on referenced item | `[RE:DEPEND P0003]` |

**Semantic constraints (enforced by DB):**

| ref_type | Valid targets | Constraint |
|----------|---------------|------------|
| `resolve` | T only | Can only resolve a Tension |
| `reopen` | T only | Can only reopen a Tension |
| `address` | T only | Can only address a Tension |
| `refine` | same type | P→P, R→R, C→C, etc. |
| `support` | any | Flexible — endorses any entity |
| `oppose` | any | Flexible — challenges any entity |
| `question` | any | Flexible — asks clarification on any entity |
| `depend` | any | Flexible — logical dependency on any entity |

**Reference targets:**
- Global IDs for prior rounds: `P0001`, `R0001`, `T0001`, `E0001`, `C0001`
- Local IDs for same-round items: `MUFFIN-P0101`, `DONUT-E0101`, `CUPCAKE-C0101`
- Expert contributions: `@muffin` (references expert's overall position)

#### Dialogue Moves

| Marker | Description |
|--------|-------------|
| `[MOVE:DEFEND {id}]` | Strengthens case for referenced item |
| `[MOVE:CHALLENGE {id}]` | Questions assumptions in referenced item |
| `[MOVE:BRIDGE {id1} {id2}]` | Synthesizes two items into common ground |
| `[MOVE:REQUEST {topic}]` | Asks panel for specific input |
| `[MOVE:CONCEDE {id}]` | Withdraws own position in favor of referenced item |
| `[MOVE:CONVERGE]` | Signals readiness to conclude |

#### Verdicts (Judge and Expert)

| Marker | Author | Description |
|--------|--------|-------------|
| `[VERDICT:INTERIM]` | Judge | Mid-dialogue checkpoint decision |
| `[VERDICT:FINAL]` | Judge | Authoritative conclusion |
| `[DISSENT]` | Expert | Formal objection with reasoning |
| `[MINORITY VERDICT: label]` | Expert coalition | Alternative recommendation |

---

#### Example: Complete Expert Response

```markdown
# Muffin - Value Analyst (Round 1)

[MUFFIN-P0101: Options viability confirmed]
The 30-delta covered call strategy can generate 18-34% annualized income,
effectively bridging the income mandate gap. This addresses my original
concern from P0001.

[RE:REFINE P0001]
My round 0 perspective on income mandate mismatch evolves: the gap is
bridgeable with derivatives, not insurmountable as I initially framed.

[RE:SUPPORT R0001]
Donut's collar structure is sound. The 45 DTE recommendation optimizes
theta decay while maintaining flexibility.

[RE:ADDRESS T0001]
With the options overlay generating 18-34% annualized, the 4% income
mandate can be satisfied. I believe T0001 is addressable pending
execution details.

[MUFFIN-E0101: Historical options premium data]
- NVDA 30-day ATM IV averaged 45% over past 24 months
- 30-delta calls yielded 2.1-2.8% monthly premium
- Premium remained viable even during Q4 2022 drawdown

[RE:SUPPORT MUFFIN-P0101]
This data supports my options viability perspective.

[MUFFIN-T0101: Execution timing constraint]
Post-refinancing window creates 60-90 day delay. Optimal entry may
conflict with covenant restrictions.

[MOVE:BRIDGE P0003 R0001]
Cupcake's concentration concern and Donut's collar proposal can be
reconciled: phased entry over 6 months limits concentration while
allowing options strategy to scale.

[MUFFIN-C0101: Income mandate resolved]
The income mandate objection is resolved via options overlay. Remaining
concerns are execution timing and concentration—both manageable with
phased approach.

[RE:DEPEND MUFFIN-P0101]
[RE:DEPEND MUFFIN-E0101]
```

#### Stored Relationships

Cross-references are stored in the database and exported:

```json
{
  "id": "P0101",
  "label": "Options viability confirmed",
  "contributors": ["muffin"],
  "references": [
    { "type": "refine", "target": "P0001" },
    { "type": "support", "target": "R0001" },
    { "type": "address", "target": "T0001" }
  ],
  "moves": [
    { "type": "bridge", "targets": ["P0003", "R0001"] }
  ]
}
```

**Parsing priority:** The export parser extracts markers in order of appearance, maintaining expert voice while enabling structured analysis.

## Portability

This schema is designed for future migration to DynamoDB (see ADR 0017).

**Single-table pattern:**
```
PK: dialogue_id
SK: TYPE#subkey

nvidia-dec | META                  → dialogue metadata
nvidia-dec | EXPERT#muffin         → expert info, total score
nvidia-dec | ROUND#0               → round metadata, score, velocity
nvidia-dec | RSCORE#0#muffin       → expert score for round 0
nvidia-dec | PERSP#0#muffin#1      → perspective (round#expert#seq)
nvidia-dec | REC#0#donut#1         → recommendation (round#expert#seq)
nvidia-dec | CONTRIB#0#muffin#evidence#1 → contribution (non-first-class)
nvidia-dec | TENSION#T0001           → tension
nvidia-dec | TEVENT#T0001#1706900000 → tension event
nvidia-dec | REF#P0101#support#R0001 → cross-reference (source#type#target)
nvidia-dec | VERDICT#final         → verdict
nvidia-dec | VERDICT#minority-esg  → minority verdict
```

**Design constraints for portability:**
1. All queries scoped to single `dialogue_id` (partition key)
2. Composite sort keys encode hierarchy (`TYPE#subkey`)
3. No cross-dialogue JOINs in hot path
4. Judge performs all writes (single writer per dialogue)

**Why Judge writes all data:**
- Agents run in parallel and could cause write contention
- Judge already reads all agent outputs for scoring
- Single writer eliminates race conditions on `seq` assignment
- SQLite and DynamoDB both benefit from this pattern

See RFC 0053 for the storage abstraction layer (future work).

## Calibration (RFC 0054)

This RFC defines **uncalibrated** dialogues — experts argue freely without domain-specific guardrails. RFC 0054 extends this with **calibrated** dialogues using:

| Concept | Description |
|---------|-------------|
| **Principle** | Universal truths (inter-domain) |
| **Tenet** | Domain-specific norms ("the way we do things") |
| **Constraint** | Question-specific requirements |
| **Ethos** | Synthesized, conflict-free rule set for a dialogue |

**Impact on this RFC:**

1. **Schema**: `dialogues` table gains `calibrated`, `domain_id`, `ethos_id` columns
2. **Context fetch**: `blue_dialogue_round_context` returns `calibration` block with ethos rules
3. **Prompts**: Calibrated dialogues inject ethos into expert prompts
4. **Verdicts**: `ethos_compliance` field tracks compliance and exceptions
5. **Scoring**: Judge may apply calibration modifiers (ethos violations, bonuses)

**Authoring**: Principles, tenets, and constraints are authored via the `/ethos` skill (see RFC 0054).

## Implementation

### Phase 1: Schema
- [ ] Add `dialogues` root table with collision-safe ID generation
- [ ] Add `experts`, `rounds`, `expert_round_scores` tables
- [ ] Add `perspectives`, `tensions`, `tension_events` tables
- [ ] Add `recommendations` table (first-class, links to tensions/perspectives)
- [ ] Add `evidence`, `claims` tables (first-class entities)
- [ ] Add `refs` table for explicit cross-references between entities
- [ ] Add `contributions`, `verdicts` tables
- [ ] Add foreign key constraints to enforce referential integrity
- [ ] Add indices for common query patterns (including refs target/source indices)

### Phase 2: MCP Tools (Public API)
- [ ] `blue_dialogue_create` - creates dialogue, registers experts from pool
- [ ] `blue_dialogue_round_context` - **bulk fetch** context for all panel experts
- [ ] `blue_dialogue_expert_create` - create new expert mid-dialogue (Judge only)
- [ ] `blue_dialogue_round_register` - **bulk register** all round data in single call
- [ ] `blue_dialogue_verdict_register` - register interim/final/minority verdicts
- [ ] `blue_dialogue_export` - generate JSON export from database

### Phase 2b: Internal Functions (called by public tools)
- [ ] `perspective_register` - called by `round_register`
- [ ] `recommendation_register` - called by `round_register`
- [ ] `tension_register` - called by `round_register`
- [ ] `tension_update` - called by `round_register`
- [ ] `evidence_register` - called by `round_register`
- [ ] `claim_register` - called by `round_register`
- [ ] `ref_register` - called by `round_register`
- [ ] `recommendation_update` - called by `round_register`, `verdict_register`

### Phase 2c: Validation Layer
- [ ] Implement MCP-layer validation with structured error responses
- [ ] Implement batch validation (all errors returned, not just first)
- [ ] Add error codes and message templates per constraint type

### Phase 3: Lifecycle Tracking
- [ ] Implement tension state machine (open → addressed → resolved)
- [ ] Create `tension_events` audit trail
- [ ] Add authority checks for resolution confirmation
- [ ] Support verdict types: interim, final, minority, dissent

### Phase 4: Export Tooling
- [ ] Implement `blue_dialogue_export` MCP tool
- [ ] Query all data from database (no file parsing)
- [ ] Generate single dialogue.json with all data (perspectives, recommendations, tensions, evidence, claims, verdicts, raw content)
- [ ] Validation and warning reporting
- [ ] Integration with superviber-web demo viewer

### Phase 5: Skill & Documentation Updates
- [ ] Create `alignment-expert` skill with static marker syntax:
  - First-class entity markers (P, R, T, E, C)
  - Cross-reference syntax (RE:SUPPORT, RE:OPPOSE, etc.)
  - Dialogue move syntax (MOVE:DEFEND, MOVE:BRIDGE, etc.)
  - Verdict markers (DISSENT, MINORITY VERDICT)
  - Local ID format rules
- [ ] Update `alignment-play` skill with new workflow:
  - Judge fetches data via `blue_dialogue_round_context`
  - Judge builds prompts, writes to filesystem for debugging
  - Judge spawns agents with full prompt + `alignment-expert` skill
  - Judge calls `blue_dialogue_round_register` after scoring (bulk registration)
  - Two-phase ID system: agents write local IDs, Judge registers global IDs
  - Dynamic expert creation via `blue_dialogue_expert_create`
- [ ] Document tool parameters and return values
- [ ] Add examples for common workflows

### Phase 6: Tooling & Analysis
- [ ] Citation auto-expansion (short form → composite key)
- [ ] Visualization dashboard integration
- [ ] Cross-dialogue analysis queries
- [ ] Real-time dialogue monitoring dashboard

## Test Plan

- [ ] **Dialogue ID uniqueness**: Creating dialogue with duplicate title generates suffixed ID
- [ ] **Output directory isolation**: Concurrent dialogues don't overwrite each other's files
- [ ] Composite keys are unique across dialogue
- [ ] Display IDs derived correctly from composite keys
- [ ] Tension lifecycle transitions respect authority rules
- [ ] Reopened tensions preserve original ID and history
- [ ] JSON export backward compatible with existing consumers
- [ ] SQLite indices performant for 100+ perspective dialogues
- [ ] Foreign key constraints prevent orphaned perspectives/tensions
- [ ] **Agent Context**: `blue_dialogue_round_context` returns context for ALL panel experts in one call
- [ ] **Agent Context**: Shared data (dialogue, prior_rounds, tensions) not duplicated per expert
- [ ] **Agent Context**: Per-expert data (role, focus, source, round_context) keyed by slug
- [ ] **Agent Context**: All prompts include `dialogue.background` (subject, constraints, situation)
- [ ] **Agent Context**: Prompts are self-contained — no external knowledge required
- [ ] **Agent Context**: All agents receive structured content with global IDs (no raw_content)
- [ ] **Agent Context**: All agents receive structured perspectives/proposals with full `content` field
- [ ] **Agent Context**: Fresh experts receive same prior_rounds data as retained experts
- [ ] **Agent Context**: Judge writes context brief for fresh experts (pool or created)
- [ ] **Agent Context**: Active tensions include involvement indicator
- [ ] **Expert Creation**: Judge can create new experts mid-dialogue via MCP
- [ ] **Expert Creation**: Created experts have `source: "created"` and `creation_reason`
- [ ] **Expert Creation**: Judge writes context brief with mandate for created experts
- [ ] **Expert Creation**: Context brief includes dialogue question and foundational context
- [ ] **Expert Creation**: Context brief includes constraints, background, current situation
- [ ] **Expert Creation**: Fresh experts are self-sufficient (no "what is this about?" gaps)
- [ ] **Expert Creation**: Created experts can participate starting from any round
- [ ] **Expert Creation**: `first_round` tracks when expert joined
- [ ] **Prompt Assembly**: Judge builds prompts from `blue_dialogue_round_context` data
- [ ] **Prompt Assembly**: Judge writes `prompt-{expert}.md` to disk for debugging
- [ ] **Prompt Assembly**: Judge writes `context-{expert}.json` to disk for debugging
- [ ] **Prompt Assembly**: Markdown prompt includes full content from all prior experts
- [ ] **Prompt Assembly**: Markdown prompt is LLM-friendly (headers, tables, clear structure)
- [ ] **Prompt Assembly**: Judge spawns agents with full prompt + `alignment-expert` skill
- [ ] **Prompt Assembly**: Agents don't need to read files — prompt passed directly
- [ ] **Prompt Assembly**: Agent writes response to `response-{expert}.md`
- [ ] **Skill**: `alignment-expert` skill contains static marker syntax reference
- [ ] **Skill**: Skill loaded once per agent, not repeated in every prompt
- [ ] **Registration**: Perspectives registered with correct composite keys
- [ ] **Proposals**: Proposals have first-class status with global IDs (EXPERT-R0001)
- [ ] **Proposals**: Proposals link to tensions they address
- [ ] **Proposals**: Proposals link to perspectives they build on
- [ ] **Proposals**: Proposal status tracks proposed → adopted/rejected
- [ ] **Proposals**: Adopted proposals linked to verdict
- [ ] **Registration**: Contributions (proposals, evidence, moves) stored with parameters
- [ ] **Registration**: Round completion updates expert scores and dialogue total
- [ ] **Registration**: Tension events create audit trail
- [ ] **Export**: Single dialogue.json contains all sections (experts, rounds, perspectives, recommendations, tensions, evidence, claims, verdicts)
- [ ] **Export**: Global perspective IDs are unique and sequential
- [ ] **Export**: All data comes from database queries (no file parsing)
- [ ] **Export**: Perspective status correctly tracks refinements across rounds
- [ ] **Export**: Proposals include structured parameters from contributions table
- [ ] **Export**: Cross-references build relationship graph between expert contributions
- [ ] **Refs**: Cross-references stored in `refs` table with typed relationships
- [ ] **Refs**: Query "what supports P0001?" uses target index efficiently
- [ ] **Refs**: Query "what does P0101 reference?" uses source index efficiently
- [ ] **Refs**: ref_type constrained to valid types (support, oppose, refine, etc.)
- [ ] **Refs**: Type consistency enforced (source_type='P' requires source_id LIKE 'P%')
- [ ] **Refs**: Semantic constraint: resolve/reopen/address must target Tension (T)
- [ ] **Refs**: Semantic constraint: refine must be same-type (P→P, R→R, etc.)
- [ ] **Refs**: Invalid combo rejected (e.g., `P resolve→ P` fails CHECK)
- [ ] **Errors**: MCP returns structured error with `error_code`, `message`, `suggestion`
- [ ] **Errors**: Type enum violations return `invalid_entity_type` or `invalid_ref_type`
- [ ] **Errors**: Type/ID mismatch returns `type_id_mismatch` with expected prefix
- [ ] **Errors**: Semantic violations return `invalid_ref_target` with valid options
- [ ] **Errors**: Batch operations return all validation errors, not just first
- [ ] **Errors**: Judge can parse error response and correct submission programmatically
- [ ] **Verdicts**: Multiple verdicts per dialogue supported
- [ ] **Verdicts**: Interim verdicts can be registered mid-dialogue
- [ ] **Verdicts**: Minority verdicts capture dissenting coalition
- [ ] **Verdicts**: Verdicts are immutable once registered
- [ ] **Verdicts**: Export includes all verdicts in chronological order

## Dialogue Summary

This RFC was designed through a 5-expert alignment dialogue:

| Expert | Role | Key Contribution |
|--------|------|------------------|
| Cupcake | Traceability Analyst | Composite key design, lifecycle rules |
| Muffin | API Designer | JSON export schema, API contract |
| Brioche | Data Architect | SQLite schema, event audit trail |
| Donut | Skeptic | Challenged assumptions, surfaced lifecycle gap |
| Scone | Performance Engineer | Indexing strategy |
| Eclair | UX Advocate | Human-readable ID advocacy |

**Key tensions resolved:**
- Prefixed vs Sequential IDs → Storage/display split
- Real-time vs Snapshot tracking → Two-layer architecture
- Merge conflicts → Composite keys
- Lifecycle underspecified → Four-state machine with events

---

*"The blind men now have coordinates. Each can say exactly which part of the elephant they touched."*
