blue/.blue/docs/rfcs/0051-global-perspective-tension-tracking.accepted.md
Eric Garcia 1447a2a6d2 test: RFC 0051 performance & isolation tests
Added:
- Performance indices on all entity tables for fast dialogue lookups
- test_output_directory_isolation: Unique IDs ensure separate output dirs
- test_performance_many_perspectives: 100 perspectives queried under 100ms
- test_indices_exist: Verify all performance indices created
- test_no_orphaned_entities: Refs connect valid entities

All pending tests complete. RFC 0051 fully implemented.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 18:53:13 -05:00

102 KiB

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}

[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

-- ================================================================
-- 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

{
  "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:

{
  "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:

{
  "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_idglobal_id

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:

{
  "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:

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

Returns:

{
  "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:

{
  "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
{
  "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:

// 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:

# 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

# 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:

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

{
  "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:

## 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:

# 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:

{
  "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

{
  "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:

{
  "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:

[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 openrefined / conceded / merged
Recommendation proposedamendedadopted / rejected
Tension openaddressedresolved / reopened
Evidence citedchallengedconfirmed / refuted
Claim assertedsupported / opposedadopted / 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

# 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:

{
  "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 Complete

  • 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)

Implementation Notes:

  • Schema migration v8→v9 in crates/blue-core/src/store.rs
  • 13 new tables: alignment_dialogues, alignment_experts, alignment_rounds, alignment_perspectives, alignment_perspective_events, alignment_tensions, alignment_tension_events, alignment_recommendations, alignment_recommendation_events, alignment_evidence, alignment_claims, alignment_refs, alignment_verdicts
  • All DB operations in crates/blue-core/src/alignment_db.rs (1400+ lines)

Phase 2: MCP Tools (Public API) Complete

  • 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

Implementation Notes:

  • Tool definitions in crates/blue-mcp/src/server.rs (lines 1795-2000)
  • Handler implementations in crates/blue-mcp/src/handlers/dialogue.rs
  • All handlers use ProjectState for DB access via state.store.conn()

Phase 2b: Internal Functions Complete

  • register_perspective - called by round_register
  • register_recommendation - called by round_register
  • register_tension - called by round_register
  • update_tension_status - called by round_register
  • register_evidence - called by round_register
  • register_claim - called by round_register
  • register_ref - called by round_register
  • register_verdict - called by verdict_register

Implementation Notes:

  • All functions in crates/blue-core/src/alignment_db.rs
  • Auto-generates display IDs (P0101, T0203, etc.)
  • Creates event audit trails for perspectives, tensions, recommendations

Phase 2c: Validation Layer Complete

  • 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

Implementation Notes:

  • ValidationError struct with code, message, field, suggestion, context
  • ValidationErrorCode enum: MissingField, InvalidEntityType, InvalidRefType, TypeIdMismatch, InvalidRefTarget, InvalidDisplayId, etc.
  • ValidationCollector for batch error collection
  • validate_ref_semantics() enforces: resolve/reopen/address → Tension, refine → same-type
  • validate_display_id() validates format and extracts components
  • handle_round_register returns all validation errors in structured JSON before DB operations
  • 8 new validation tests added (20 total alignment_db tests)

Phase 3: Lifecycle Tracking Complete

  • Implement tension state machine (open → addressed → resolved → reopened)
  • Create tension_events audit trail
  • Add authority checks for resolution confirmation (via actors parameter)
  • Support verdict types: interim, final, minority, dissent

Implementation Notes:

  • TensionStatus enum: Open, Addressed, Resolved, Reopened
  • Events stored with actors, reference, and round number
  • VerdictType enum: Interim, Final, Minority, Dissent

Phase 4: Export Tooling Complete

  • 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)
  • Validation and warning reporting
  • Integration with superviber-web demo viewer

Implementation Notes:

  • handle_export() in crates/blue-mcp/src/handlers/dialogue.rs
  • Writes to {output_dir}/{dialogue_id}/dialogue.json by default
  • Full provenance: includes created_at, refs, status for all entities

Phase 5: Skill & Documentation Updates Complete

  • 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 with context from DB
    • Judge spawns agents with full prompt + alignment-expert skill reference
    • 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 in skill file
  • Add examples for DB-backed workflow

Implementation Notes:

  • skills/alignment-expert/SKILL.md - full marker syntax reference
  • skills/alignment-play/SKILL.md - updated with DB-backed workflow, two-phase ID system, tool documentation
  • Both skills reference each other for complete workflow

Phase 6: Tooling & Analysis

  • Citation auto-expansion (short form → composite key)
  • Visualization dashboard integration (requires external UI)
  • Cross-dialogue analysis queries
  • Real-time dialogue monitoring dashboard

Implementation Notes:

  • expand_citation() and expand_citations() - expand display ID to full entity context (label, content, contributors, status)
  • get_cross_dialogue_stats() - aggregated statistics across all dialogues (entity counts, averages, top experts)
  • find_similar_dialogues() - text-based search across dialogue titles and tension labels
  • get_dialogue_progress() - real-time status including velocity, convergence detection, leaderboard, estimated rounds remaining
  • Tests: test_expand_citation_*, test_cross_dialogue_stats, test_dialogue_progress*, test_find_similar_dialogues

Test Plan

Core Schema Tests (12 unit tests in alignment_db::tests)

  • Dialogue ID uniqueness: Creating dialogue with duplicate title generates suffixed ID (test_generate_dialogue_id)
  • Display IDs derived correctly from composite keys (test_display_id_format, test_parse_display_id)
  • Tension lifecycle transitions work correctly (test_tension_lifecycle)
  • Cross-references stored and retrieved (test_cross_references)
  • Expert registration and scores (test_register_expert, test_expert_scores)
  • Perspective registration (test_register_perspective)
  • Tension registration (test_register_tension)
  • Verdict registration (test_verdict_registration)
  • Full dialogue workflow (test_full_dialogue_workflow)
  • Create and get dialogue (test_create_and_get_dialogue)

MCP Tool Tests (Integration)

  • Agent Context: blue_dialogue_round_context returns context for ALL panel experts in one call
  • Agent Context: Shared data (dialogue, prior_rounds, tensions) included
  • Agent Context: Returns structured perspectives/recommendations with full content field
  • Expert Creation: Judge can create new experts mid-dialogue via MCP
  • Expert Creation: Created experts have source: "created" and creation_reason
  • Expert Creation: first_round tracks when expert joined
  • Registration: Perspectives registered with correct display IDs (P0101, P0201, etc.)
  • 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 IDs are unique and sequential
  • Export: All data comes from database queries (no file parsing)
  • Refs: Cross-references stored in refs table with typed relationships
  • Refs: ref_type constrained to valid types (support, oppose, refine, etc.)
  • Verdicts: Multiple verdicts per dialogue supported
  • Verdicts: Interim verdicts can be registered mid-dialogue
  • Verdicts: Minority verdicts capture dissenting coalition
  • Verdicts: Export includes all verdicts in chronological order

Validation Layer Tests (Phase 2c) Complete

  • 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: Structured JSON response allows Judge to parse and correct programmatically
  • 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 caught with appropriate error (e.g., P resolve→ P returns InvalidRefTarget)

Skill Integration Tests (Phase 5) Complete

  • Skill: alignment-expert skill contains static marker syntax reference
  • Skill: Skill can be loaded once per agent via skill reference
  • Prompt Assembly: Judge builds prompts from blue_dialogue_round_context data (documented workflow)
  • Prompt Assembly: Markdown prompt includes full content from all prior experts (via round_context)
  • Prompt Assembly: Judge spawns agents with full prompt + alignment-expert skill reference
  • Prompt Assembly: Judge writes prompt-{expert}.md to disk for debugging (optional enhancement)

Phase 6: Tooling Tests Complete

  • Citation Expansion: expand_citation returns full entity context from display ID (test_expand_citation_perspective)
  • Citation Expansion: Tensions include status field (test_expand_citation_tension)
  • Citation Expansion: Recommendations include parameters (test_expand_citation_recommendation_with_params)
  • Citation Expansion: Batch expansion returns errors for invalid IDs (test_expand_multiple_citations)
  • Cross-Dialogue: Statistics aggregate across all dialogues (test_cross_dialogue_stats)
  • Cross-Dialogue: Similar dialogues found by text search (test_find_similar_dialogues)
  • Progress Tracking: Real-time progress includes velocity and convergence (test_dialogue_progress)
  • Progress Tracking: Convergence detected when velocity near zero (test_dialogue_progress_convergence)

Performance & Isolation Tests Complete

  • Output directory isolation: Unique dialogue IDs ensure separate output dirs (test_output_directory_isolation)
  • SQLite indices exist for all key lookups (test_indices_exist)
  • 100+ perspective queries complete under 100ms (test_performance_many_perspectives)
  • No orphaned entities - refs connect valid entities (test_no_orphaned_entities)

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."