diff --git a/.blue/docs/rfcs/0051-global-perspective-tension-tracking.draft.md b/.blue/docs/rfcs/0051-global-perspective-tension-tracking.draft.md new file mode 100644 index 0000000..1d1d282 --- /dev/null +++ b/.blue/docs/rfcs/0051-global-perspective-tension-tracking.draft.md @@ -0,0 +1,2592 @@ +# RFC 0051: Global Perspective & Tension Tracking + +| | | +|---|---| +| **Status** | Draft | +| **Date** | 2026-02-02 | +| **ADRs** | 0014 (Alignment Dialogue Agents), 0005 (Single Source), 0018 (DynamoDB-Portable Schema) | +| **Extends** | RFC 0048 (Expert Pools), RFC 0050 (Graduated Rotation) | +| **Extended By** | RFC 0054 (Calibrated Alignment — Ethos & Tenets) | +| **Dialogue** | 2047 (5 experts, 3 rounds, ALIGNMENT 427) | + +--- + +## Summary + +The alignment dialogue system currently tracks perspectives and tensions within round summaries, making cross-dialogue analysis difficult. This RFC introduces **global perspective and tension tracking** with: + +1. **Two-phase ID assignment**: Agents write local IDs (`MUFFIN-P0001`), Judge registers with global IDs (`P0001`) +2. **Global IDs**: `P0001`, `R0001`, `T0001` — sequential per round, expert in data not ID +3. **DB-first architecture**: All data registered via MCP tools, agents get context from DB +4. **First-class entities**: Perspectives (P), recommendations (R), tensions (T), evidence (E), claims (C) with full lifecycle +5. **LLM-friendly transcripts**: MCP generates markdown context, writes to disk for debugging +6. **Dynamic expert creation**: Judge can create experts mid-dialogue to address emerging needs +7. **JSON export**: Full provenance from database queries (no file parsing) +8. **Calibration support**: Optional ethos integration for calibrated dialogues (see RFC 0054) + +## Problem + +In the NVIDIA Investment Decision dialogue: +- 24 perspectives surfaced across 3 rounds from 12 experts +- 12 tensions raised and resolved +- **No global numbering**: P01 in round 0 vs P01 in round 1 are ambiguous +- **No origin tracking**: "Who said this?" requires reading full transcripts +- **No lifecycle visibility**: When was T0003 resolved? By whom? + +The reference export format (`dialogue.json`) lacks these fields, making it unsuitable for: +- Cross-dialogue analysis +- Visualization dashboards +- Audit and compliance review + +## Design + +### Core Principle: Two-Phase ID Assignment + +**Phase 1 — Agents write with local IDs:** `{UPPER(expert)}-{TYPE}{round:02d}{seq:02d}` +```markdown +[MUFFIN-P0001: Income mandate mismatch] +[DONUT-R0001: Options collar] +[MUFFIN-T0001: Growth vs income] +[MUFFIN-E0001: Historical IV data] +[MUFFIN-C0001: Income gap is bridgeable] +``` + +**Phase 2 — Judge registers, MCP assigns global IDs:** +``` +P0001, P0002, P0003... (perspectives, sequential per round) +R0001, R0002... (recommendations, sequential per round) +T0001, T0002... (tensions, sequential per round) +E0001, E0002... (evidence, sequential per round) +C0001, C0002... (claims, sequential per round) +``` + +**Storage key:** `(dialogue_id, round, seq)` with `expert_slug` as attribution + +**Display ID:** `P{round:02d}{seq:02d}` — first 2 digits = round, last 2 digits = seq +- `P0001` = round 0, seq 1 +- `P0102` = round 1, seq 2 +- `P0215` = round 2, seq 15 + +Expert attribution is stored in the record, not encoded in the ID. All downstream references use global IDs. + +### Schema + +```sql +-- ================================================================ +-- DIALOGUES (root table - enforces unique dialogue_id) +-- ================================================================ +CREATE TABLE dialogues ( + dialogue_id TEXT PRIMARY KEY, -- slug derived from title + title TEXT NOT NULL, + question TEXT, + status TEXT NOT NULL DEFAULT 'open', + created_at TEXT NOT NULL, + converged_at TEXT, + total_rounds INT DEFAULT 0, + total_alignment INT DEFAULT 0, + output_dir TEXT, -- /tmp/blue-dialogue/{slug} + + -- Calibration (RFC 0054) + calibrated BOOLEAN DEFAULT FALSE, + domain_id TEXT, -- FK to domains table (RFC 0054) + ethos_id TEXT, -- FK to ethos table (RFC 0054) + + CHECK (status IN ('open', 'converging', 'converged', 'abandoned')) +); + +-- ================================================================ +-- VERDICTS (first-class entities, supports multiple per dialogue) +-- ================================================================ +CREATE TABLE verdicts ( + dialogue_id TEXT NOT NULL, + verdict_id TEXT NOT NULL, -- V01, V02, or slug like "final", "minority" + verdict_type TEXT NOT NULL, -- interim | final | minority | dissent + round INT NOT NULL, -- round when verdict was issued + author_expert TEXT, -- expert who authored (null = Judge) + recommendation TEXT NOT NULL, -- one-line decision + description TEXT NOT NULL, -- reasoning summary (2-3 sentences) + conditions JSON, -- ["condition1", "condition2"] + vote TEXT, -- "11-1", "unanimous" + confidence TEXT, -- unanimous | strong | split | contested + tensions_resolved JSON, -- ["T0001", "T0002"] + tensions_accepted JSON, -- ["T0006"] - acknowledged but not blocking + recommendations_adopted JSON, -- ["R0001"] + key_evidence JSON, -- ["E0001", "E0101"] - evidence supporting verdict + key_claims JSON, -- ["C0001", "C0101"] - claims adopted in verdict + supporting_experts JSON, -- ["muffin", "cupcake", ...] for minority verdicts + + -- Ethos compliance (RFC 0054) — only for calibrated dialogues + ethos_compliance JSON, -- {"fully_compliant": bool, "exceptions": [...], "violations": [...]} + + created_at TEXT NOT NULL, + PRIMARY KEY (dialogue_id, verdict_id), + FOREIGN KEY (dialogue_id) REFERENCES dialogues(dialogue_id), + CHECK (verdict_type IN ('interim', 'final', 'minority', 'dissent')) +); + +-- Prevent exact duplicate titles at same timestamp +CREATE UNIQUE INDEX idx_dialogues_title_created + ON dialogues(title, created_at); + +-- ================================================================ +-- EXPERTS (participation and scores per dialogue) +-- ================================================================ +CREATE TABLE experts ( + dialogue_id TEXT NOT NULL, + expert_slug TEXT NOT NULL, -- muffin, cupcake, etc. (capitalize for display) + role TEXT NOT NULL, -- Value Analyst, Risk Manager, etc. + description TEXT, -- detailed role description + focus TEXT, -- brief focus area + tier TEXT NOT NULL, -- Core, Adjacent, Wildcard + source TEXT NOT NULL, -- pool | created + relevance REAL, -- 0.0-1.0 (from pool, or Judge-assigned for created) + creation_reason TEXT, -- why Judge created this expert (null if from pool) + color TEXT, -- hex color for UI + scores JSON, -- {"0": 12, "1": 8, "2": 15} - per-round scores + raw_content JSON, -- {"0": "markdown...", "1": "markdown..."} - per-round responses + total_score INT DEFAULT 0, -- computed: sum of scores (denormalized) + first_round INT, -- round when expert first participated + created_at TEXT NOT NULL, + PRIMARY KEY (dialogue_id, expert_slug), + FOREIGN KEY (dialogue_id) REFERENCES dialogues(dialogue_id), + CHECK (tier IN ('Core', 'Adjacent', 'Wildcard')), + CHECK (source IN ('pool', 'created')) +); + +-- ================================================================ +-- ROUNDS (metadata and scores per round) +-- ================================================================ +CREATE TABLE rounds ( + dialogue_id TEXT NOT NULL, + round INT NOT NULL, + title TEXT, -- "Opening Arguments", "Refinement", etc. + score INT NOT NULL, -- ALIGNMENT score for this round + summary TEXT, -- Judge's synthesis + status TEXT NOT NULL DEFAULT 'open', + created_at TEXT NOT NULL, + completed_at TEXT, + PRIMARY KEY (dialogue_id, round), + FOREIGN KEY (dialogue_id) REFERENCES dialogues(dialogue_id), + CHECK (status IN ('open', 'in_progress', 'completed')) +); + +-- ================================================================ +-- PERSPECTIVES +-- ================================================================ +CREATE TABLE perspectives ( + dialogue_id TEXT NOT NULL, + round INT NOT NULL, -- origin round + seq INT NOT NULL, -- global per round (P0001, P0002...) + label TEXT NOT NULL, + content TEXT NOT NULL, -- Judge-synthesized content + contributors JSON NOT NULL, -- ["muffin", "cupcake"] - all who contributed + status TEXT NOT NULL DEFAULT 'open', + references JSON, -- [{"type": "refine", "target": "P0001"}, ...] + created_at TEXT NOT NULL, + PRIMARY KEY (dialogue_id, round, seq), + FOREIGN KEY (dialogue_id) REFERENCES dialogues(dialogue_id), + CHECK (status IN ('open', 'refined', 'conceded', 'merged')) +); + +-- Perspective events (audit trail) +CREATE TABLE perspective_events ( + dialogue_id TEXT NOT NULL, + perspective_round INT NOT NULL, + perspective_seq INT NOT NULL, + event_type TEXT NOT NULL, -- created, refined, conceded, merged + event_round INT NOT NULL, -- round when event occurred + actors JSON NOT NULL, -- ["muffin"] - who triggered this event + result_id TEXT, -- e.g., "P0101" if refined into new perspective + created_at TEXT NOT NULL, + PRIMARY KEY (dialogue_id, perspective_round, perspective_seq, created_at), + FOREIGN KEY (dialogue_id, perspective_round, perspective_seq) + REFERENCES perspectives(dialogue_id, round, seq), + CHECK (event_type IN ('created', 'refined', 'conceded', 'merged')) +); + +CREATE INDEX idx_perspectives_dialogue_round + ON perspectives(dialogue_id, round, created_at); + +-- ================================================================ +-- TENSIONS +-- ================================================================ +CREATE TABLE tensions ( + dialogue_id TEXT NOT NULL, + round INT NOT NULL, -- origin round + seq INT NOT NULL, -- global per round (T0001, T0002...) + label TEXT NOT NULL, + description TEXT NOT NULL, -- Judge-synthesized description + contributors JSON NOT NULL, -- ["muffin", "cupcake"] - all who surfaced this + status TEXT NOT NULL DEFAULT 'open', + references JSON, -- [{"type": "depend", "target": "P0001"}, ...] + created_at TEXT NOT NULL, + PRIMARY KEY (dialogue_id, round, seq), + FOREIGN KEY (dialogue_id) REFERENCES dialogues(dialogue_id), + CHECK (status IN ('open', 'addressed', 'resolved', 'reopened')) +); + +-- Display ID: T{round:02d}{seq:02d} +-- e.g., T0001, T0102 + +CREATE INDEX idx_tensions_status ON tensions(dialogue_id, status); + +-- ================================================================ +-- MOVES (dialogue moves: defend, challenge, bridge, etc.) +-- ================================================================ +CREATE TABLE moves ( + dialogue_id TEXT NOT NULL, + round INT NOT NULL, + seq INT NOT NULL, + expert_slug TEXT NOT NULL, + move_type TEXT NOT NULL, -- defend, challenge, bridge, request, concede, converge + targets JSON NOT NULL, -- ["P0001", "R0001"] - IDs this move references + context TEXT, -- brief explanation + created_at TEXT NOT NULL, + PRIMARY KEY (dialogue_id, round, expert_slug, seq), + FOREIGN KEY (dialogue_id) REFERENCES dialogues(dialogue_id), + CHECK (move_type IN ('defend', 'challenge', 'bridge', 'request', 'concede', 'converge')) +); + +-- ================================================================ +-- RECOMMENDATIONS (first-class, links to tensions and perspectives) +-- ================================================================ +CREATE TABLE recommendations ( + dialogue_id TEXT NOT NULL, + round INT NOT NULL, -- origin round + seq INT NOT NULL, -- global per round (R0001, R0002...) + label TEXT NOT NULL, + content TEXT NOT NULL, -- Judge-synthesized content + contributors JSON NOT NULL, -- ["donut", "muffin"] - all who contributed + parameters JSON, -- structured data (e.g., options parameters) + status TEXT NOT NULL DEFAULT 'proposed', + references JSON, -- [{"type": "refine", "target": "R0001"}, {"type": "address", "target": "T0001"}, ...] + adopted_in_verdict TEXT, -- verdict_id if adopted + created_at TEXT NOT NULL, + PRIMARY KEY (dialogue_id, round, seq), + FOREIGN KEY (dialogue_id) REFERENCES dialogues(dialogue_id), + CHECK (status IN ('proposed', 'amended', 'adopted', 'rejected')) +); + +-- Recommendation events (audit trail) +CREATE TABLE recommendation_events ( + dialogue_id TEXT NOT NULL, + rec_round INT NOT NULL, + rec_seq INT NOT NULL, + event_type TEXT NOT NULL, -- created, amended, adopted, rejected + event_round INT NOT NULL, + actors JSON NOT NULL, -- who triggered this event + result_id TEXT, -- new recommendation ID if amended + created_at TEXT NOT NULL, + PRIMARY KEY (dialogue_id, rec_round, rec_seq, created_at), + FOREIGN KEY (dialogue_id, rec_round, rec_seq) + REFERENCES recommendations(dialogue_id, round, seq), + CHECK (event_type IN ('created', 'amended', 'adopted', 'rejected')) +); + +-- Display ID: R{round:02d}{seq:02d} +-- e.g., R0001, R0102 + +CREATE INDEX idx_recommendations_status + ON recommendations(dialogue_id, status); + +-- ================================================================ +-- EVIDENCE (first-class: data, precedents, facts) +-- ================================================================ +CREATE TABLE evidence ( + dialogue_id TEXT NOT NULL, + round INT NOT NULL, + seq INT NOT NULL, -- global per round (E0001, E0002...) + label TEXT NOT NULL, + content TEXT NOT NULL, -- the data/facts + contributors JSON NOT NULL, -- ["muffin"] + status TEXT NOT NULL DEFAULT 'cited', + references JSON, -- [{"type": "support", "target": "P0001"}] + created_at TEXT NOT NULL, + PRIMARY KEY (dialogue_id, round, seq), + FOREIGN KEY (dialogue_id) REFERENCES dialogues(dialogue_id), + CHECK (status IN ('cited', 'challenged', 'confirmed', 'refuted')) +); + +-- Display ID: E{round:02d}{seq:02d} +-- e.g., E0001, E0103 + +CREATE INDEX idx_evidence_status + ON evidence(dialogue_id, status); + +-- ================================================================ +-- CLAIMS (first-class: quotable position statements) +-- ================================================================ +CREATE TABLE claims ( + dialogue_id TEXT NOT NULL, + round INT NOT NULL, + seq INT NOT NULL, -- global per round (C0001, C0002...) + label TEXT NOT NULL, + content TEXT NOT NULL, -- the claim statement + contributors JSON NOT NULL, -- ["muffin"] + status TEXT NOT NULL DEFAULT 'asserted', + references JSON, -- [{"type": "depend", "target": "P0001"}] + created_at TEXT NOT NULL, + PRIMARY KEY (dialogue_id, round, seq), + FOREIGN KEY (dialogue_id) REFERENCES dialogues(dialogue_id), + CHECK (status IN ('asserted', 'supported', 'opposed', 'adopted', 'withdrawn')) +); + +-- Display ID: C{round:02d}{seq:02d} +-- e.g., C0001, C0205 + +CREATE INDEX idx_claims_status + ON claims(dialogue_id, status); + +-- ================================================================ +-- REFS (explicit cross-references between entities) +-- ================================================================ +CREATE TABLE refs ( + dialogue_id TEXT NOT NULL, + source_type TEXT NOT NULL, -- P, R, T, E, C + source_id TEXT NOT NULL, -- P0101, R0001, etc. + ref_type TEXT NOT NULL, -- support, oppose, refine, address, resolve, reopen, question, depend + target_type TEXT NOT NULL, -- P, R, T, E, C + target_id TEXT NOT NULL, -- P0001, T0001, etc. + created_at TEXT NOT NULL, + PRIMARY KEY (dialogue_id, source_id, ref_type, target_id), + FOREIGN KEY (dialogue_id) REFERENCES dialogues(dialogue_id), + + -- Type enum constraints + CHECK (source_type IN ('P', 'R', 'T', 'E', 'C')), + CHECK (target_type IN ('P', 'R', 'T', 'E', 'C')), + CHECK (ref_type IN ('support', 'oppose', 'refine', 'address', 'resolve', 'reopen', 'question', 'depend')), + + -- Type consistency: source_type must match source_id prefix + CHECK ( + (source_type = 'P' AND source_id LIKE 'P%') OR + (source_type = 'R' AND source_id LIKE 'R%') OR + (source_type = 'T' AND source_id LIKE 'T%') OR + (source_type = 'E' AND source_id LIKE 'E%') OR + (source_type = 'C' AND source_id LIKE 'C%') + ), + + -- Type consistency: target_type must match target_id prefix + CHECK ( + (target_type = 'P' AND target_id LIKE 'P%') OR + (target_type = 'R' AND target_id LIKE 'R%') OR + (target_type = 'T' AND target_id LIKE 'T%') OR + (target_type = 'E' AND target_id LIKE 'E%') OR + (target_type = 'C' AND target_id LIKE 'C%') + ), + + -- Semantic constraints: which ref_types are valid for which targets + CHECK ( + -- Tension-only targets: resolve, reopen, address must target T + (ref_type IN ('resolve', 'reopen', 'address') AND target_type = 'T') OR + -- Same-type only: refine must be source_type = target_type + (ref_type = 'refine' AND source_type = target_type) OR + -- Flexible: support, oppose, question, depend can target anything + (ref_type IN ('support', 'oppose', 'question', 'depend')) + ) +); + +-- Query: "What supports P0001?" +CREATE INDEX idx_refs_target + ON refs(dialogue_id, target_id, ref_type); + +-- Query: "What does P0101 reference?" +CREATE INDEX idx_refs_source + ON refs(dialogue_id, source_id); + +-- ================================================================ +-- TENSION_EVENTS (lifecycle audit trail) +-- ================================================================ +CREATE TABLE tension_events ( + dialogue_id TEXT NOT NULL, + tension_round INT NOT NULL, -- round of the tension + tension_seq INT NOT NULL, -- seq of the tension + event_type TEXT NOT NULL, + event_round INT NOT NULL, -- round when event occurred + actors JSON NOT NULL, -- ["muffin", "donut"] - who triggered this + reason TEXT, + reference TEXT, -- global ID of resolving item (e.g., "P0005", "R0001") + created_at TEXT NOT NULL, + PRIMARY KEY (dialogue_id, tension_round, tension_seq, created_at), + FOREIGN KEY (dialogue_id, tension_round, tension_seq) + REFERENCES tensions(dialogue_id, round, seq), + CHECK (event_type IN ('created', 'addressed', 'resolved', 'reopened', 'commented')) +); +``` + +### Dialogue ID Collision Handling + +The `dialogue_id` is derived from the title via slugification. Collisions are handled at creation time: + +``` +Algorithm: generate_dialogue_id(title) + 1. slug = slugify(title) // "NVIDIA Analysis" → "nvidia-analysis" + 2. IF NOT EXISTS(SELECT 1 FROM dialogues WHERE dialogue_id = slug): + RETURN slug + 3. FOR i IN 1..99: + candidate = slug + "-" + i // "nvidia-analysis-2" + IF NOT EXISTS(SELECT 1 FROM dialogues WHERE dialogue_id = candidate): + RETURN candidate + 4. FAIL "Too many dialogues with similar titles" +``` + +**Output directory** follows the same pattern: +- `/tmp/blue-dialogue/{dialogue_id}/` + +This ensures: +- No file system collisions between concurrent dialogues +- Deterministic ID generation (same title → same base slug) +- Human-readable IDs (not UUIDs) + +### Tension Lifecycle + +``` + ┌──────────────┐ + │ created │ + └──────┬───────┘ + │ + ▼ + ┌──────────────┐ + ┌───────►│ open │◄───────┐ + │ └──────┬───────┘ │ + │ │ │ + │ ▼ │ + │ ┌──────────────┐ │ + │ │ addressed │────────┤ + │ └──────┬───────┘ │ + │ │ │ + │ ▼ │ + │ ┌──────────────┐ │ + └────────│ resolved │────────┘ + └──────────────┘ + │ + ▼ (if insufficient) + ┌──────────────┐ + │ reopened │ + └──────────────┘ +``` + +**Authority Rules:** +- Any expert can propose `addressed` with a resolution mechanism +- Original author or facilitator confirms `resolved` +- Reopening creates an event, preserving full history + +### JSON Export Format + +```json +{ + "id": "nvidia-investment-decision", + "title": "NVIDIA Investment Analysis", + "date": "2026-02-02", + "status": "converged", + "totalAlignment": 423, + + // Calibration (RFC 0054) — omitted if uncalibrated + "calibration": { + "calibrated": true, + "domain": "fiduciary-investment", + "ethos_id": "ethos-nvidia-001", + "rules_count": 14, + "compliance": { + "fully_compliant": false, + "exceptions": 1, + "violations": 0 + } + }, + + "experts": [ + { + "slug": "muffin", // capitalize for display: "Muffin" + "role": "Value Analyst", + "tier": "Core", + "scores": { + "0": 12, + "1": 8, + "2": 15 + }, + "total": 35 + }, + { + "slug": "palmier", + "role": "Geopolitical Risk Analyst", + "tier": "Adjacent", + "source": "created", // joined mid-dialogue + "scores": { + "2": 14 // only present in round 2 + }, + "total": 14 + } + ], + + "rounds_data": [ + { + "round": 0, + "score": 117, + "experts": { + "muffin": { + "score": 12, + "actions": [ + { "type": "perspective", "action": "created", "id": "P0001" }, + { "type": "tension", "action": "created", "id": "T0001" } + ] + }, + "cupcake": { + "score": 10, + "actions": [ + { "type": "perspective", "action": "created", "id": "P0002" }, + { "type": "tension", "action": "created", "id": "T0002" } + ] + }, + "donut": { + "score": 15, + "actions": [ + { "type": "perspective", "action": "created", "id": "P0003" }, + { "type": "recommendation", "action": "created", "id": "R0001" } + ] + } + } + }, + { + "round": 1, + "score": 45, + "experts": { + "muffin": { + "score": 8, + "actions": [ + { "type": "perspective", "action": "refined", "id": "P0101", "refines": "P0001" }, + { "type": "tension", "action": "addressed", "id": "T0001", "via": "R0001" } + ] + }, + "donut": { + "score": 10, + "actions": [ + { "type": "recommendation", "action": "amended", "id": "R0101", "amends": "R0001" }, + { "type": "tension", "action": "resolved", "id": "T0002", "via": "P0101" } + ] + } + } + } + ], + + "perspectives": [ + { + "id": "P0001", + "label": "Income mandate mismatch", + "content": "NVIDIA's zero dividend conflicts with 4% income requirement...", + "status": "refined", + "origin": { + "round": 0, + "contributors": ["muffin", "cupcake"] // Judge synthesized from both + }, + "events": [ + { "type": "created", "round": 0, "by": ["muffin", "cupcake"] }, + { "type": "refined", "round": 1, "by": ["muffin"], "result": "P0101" } + ] + } + ], + + "tensions": [ + { + "id": "T0001", + "label": "Growth vs income obligation", + "description": "NVIDIA's zero dividend conflicts with trust's 4% income requirement", + "status": "resolved", + "origin": { + "round": 0, + "contributors": ["muffin", "cupcake"] + }, + "events": [ + { "type": "created", "round": 0, "by": ["muffin", "cupcake"] }, + { "type": "addressed", "round": 1, "by": ["donut"], "reference": "R0001" }, + { "type": "resolved", "round": 2, "by": ["muffin"], "reference": "P0201" } + ], + "relatedPerspectives": ["P0001", "P0003"] + } + ], + + "recommendations": [ + { + "id": "R0001", + "label": "Income Collar Structure", + "content": "Strike Selection Framework with 30-delta covered calls...", + "parameters": { + "covered_call_delta": "0.20-0.25", + "protective_put_delta": "-0.15", + "dte": "30-45" + }, + "status": "adopted", + "origin": { + "round": 0, + "contributors": ["donut"] + }, + "events": [ + { "type": "created", "round": 0, "by": ["donut"] }, + { "type": "amended", "round": 1, "by": ["donut", "muffin"], "result": "R0101" }, + { "type": "adopted", "round": 2, "by": ["judge"], "reference": "verdict-final" } + ], + "addresses_tensions": ["T0001"], + "builds_on": ["P0001"] + } + ], + + "evidence": [ + { + "id": "E0001", + "label": "Historical options premium data", + "content": "NVDA 30-day ATM IV averaged 45% over past 24 months. 30-delta calls yielded 2.1-2.8% monthly premium.", + "status": "confirmed", + "origin": { + "round": 1, + "contributors": ["muffin"] + }, + "events": [ + { "type": "cited", "round": 1, "by": ["muffin"] }, + { "type": "confirmed", "round": 2, "by": ["donut", "brioche"] } + ], + "supports": ["P0101", "R0001"] + }, + { + "id": "E0002", + "label": "Trust covenant constraints", + "content": "Section 4.2 requires minimum 4% annual distribution. Corpus preservation clause limits equity drawdown to 15%.", + "status": "confirmed", + "origin": { + "round": 0, + "contributors": ["cupcake"] + }, + "events": [ + { "type": "cited", "round": 0, "by": ["cupcake"] }, + { "type": "confirmed", "round": 1, "by": ["muffin"] } + ], + "supports": ["T0001"] + } + ], + + "claims": [ + { + "id": "C0001", + "label": "Income mandate resolved via options", + "content": "The 4% income mandate can be satisfied through covered call premium generation, eliminating the primary objection to NVDA exposure.", + "status": "adopted", + "origin": { + "round": 1, + "contributors": ["muffin"] + }, + "events": [ + { "type": "asserted", "round": 1, "by": ["muffin"] }, + { "type": "supported", "round": 2, "by": ["donut", "brioche"] }, + { "type": "adopted", "round": 2, "by": ["judge"], "reference": "verdict-final" } + ], + "depends_on": ["E0001", "P0101", "R0001"] + }, + { + "id": "C0002", + "label": "Concentration risk manageable with phased entry", + "content": "Geographic and sector concentration concerns are mitigated by a 6-month phased entry strategy.", + "status": "adopted", + "origin": { + "round": 2, + "contributors": ["cupcake", "muffin"] + }, + "events": [ + { "type": "asserted", "round": 2, "by": ["cupcake"] }, + { "type": "supported", "round": 2, "by": ["muffin"] }, + { "type": "adopted", "round": 2, "by": ["judge"], "reference": "verdict-final" } + ], + "depends_on": ["P0003", "T0002"] + } + ] +} +``` + +### MCP Server Integration + +**Public tools (Judge-facing API):** + +| Tool | Purpose | +|------|---------| +| `blue_dialogue_create` | Start dialogue with expert pool; returns Judge Protocol | +| `blue_dialogue_round_context` | **Bulk fetch** structured data for all panel experts in one call | +| `blue_dialogue_expert_create` | Create new expert mid-dialogue to address emerging needs | +| `blue_dialogue_round_register` | **Bulk register** all round data in single call (perspectives, recommendations, tensions, evidence, claims, refs, scores) | +| `blue_dialogue_verdict_register` | Register a verdict (interim, final, minority, dissent) | +| `blue_dialogue_export` | Generate JSON export from database (no file parsing) | + +**Internal functions (not exposed as MCP tools):** + +These are implementation details called by the bulk tools above: + +| Function | Called By | +|----------|-----------| +| `perspective_register` | `round_register` | +| `recommendation_register` | `round_register` | +| `tension_register` | `round_register` | +| `tension_update` | `round_register` | +| `evidence_register` | `round_register` | +| `claim_register` | `round_register` | +| `ref_register` | `round_register` | +| `recommendation_update` | `round_register`, `verdict_register` | + +This gives the Judge a clean 6-tool API while maintaining internal composability. + +**Defaults (Judge discretion unless user overrides):** + +| Parameter | Default | User Override | +|-----------|---------|---------------| +| Panel size | Judge selects based on domain complexity | "Use 8 experts" | +| Convergence | 100% (all tensions resolved, all experts agree) | "Run to 80% convergence" | + +**100% convergence** means: +- All tensions resolved or explicitly accepted +- All experts agree with the verdict (no dissenters) + +Users can request early termination or partial convergence for faster results. + +**Verdict tool parameters:** + +```json +{ + "dialogue_id": "nvidia-decision", + "verdict_id": "final", // or "V01", "minority-esg" + "verdict_type": "final", // interim | final | minority | dissent + "round": 3, + "author_expert": null, // null = Judge, or expert slug + "recommendation": "REJECT full swap. APPROVE conditional partial trim.", + "description": "The panel unanimously rejected a full NVAI-to-NVDA swap due to income mandate mismatch...", + "conditions": [ + "Execute 60-90 days post-refinancing", + "Implement 30-delta covered calls" + ], + "vote": "12-0", + "confidence": "unanimous", + "tensions_resolved": ["T0001", "T0002", "T0003"], + "tensions_accepted": ["T0006"], + "recommendations_adopted": ["R0001"], + "supporting_experts": null // for minority verdicts: ["churro", "eclair"] +} +``` + +**Verdict types:** + +| Type | Use Case | +|------|----------| +| `interim` | Checkpoint verdict mid-dialogue (e.g., "continue with options exploration") | +| `final` | Authoritative conclusion when dialogue converges | +| `minority` | Structured dissent from subset of experts | +| `dissent` | Single expert's formal objection with reasoning | + +**Bulk round registration** (`blue_dialogue_round_register`): + +Register all round data in a single call — perspectives, recommendations, tensions, evidence, claims, scores, and events: + +```json +{ + "dialogue_id": "nvidia-decision", + "round": 1, + "score": 45, + "summary": "Panel converging on conditional approval with options overlay...", + + "expert_scores": { + "muffin": 8, + "donut": 10, + "cupcake": 7 + }, + + "perspectives": [ + { + "local_id": "MUFFIN-P0101", + "label": "Options viability confirmed", + "content": "The 30-delta covered call strategy...", + "contributors": ["muffin"], + "references": [ + { "type": "refine", "target": "P0001" }, + { "type": "support", "target": "R0001" }, + { "type": "address", "target": "T0001" } + ] + }, + { + "local_id": "CUPCAKE-P0101", + "label": "Concentration risk mitigated", + "content": "Phased entry over 6 months...", + "contributors": ["cupcake", "scone"], + "references": [ + { "type": "address", "target": "T0002" } + ] + } + ], + + "recommendations": [ + { + "local_id": "DONUT-R0101", + "label": "Amended collar structure", + "content": "Updated strike selection...", + "contributors": ["donut", "muffin"], + "parameters": { "delta": "0.25", "dte": "45" }, + "references": [ + { "type": "refine", "target": "R0001" }, + { "type": "address", "target": "T0001" }, + { "type": "depend", "target": "MUFFIN-P0101" } + ] + } + ], + + "tensions": [ + { + "local_id": "CROISSANT-T0101", + "label": "Execution timing", + "description": "Post-refinancing window constraint", + "contributors": ["croissant"], + "references": [ + { "type": "depend", "target": "R0001" } + ] + } + ], + + "evidence": [ + { + "local_id": "MUFFIN-E0101", + "label": "Historical options premium data", + "content": "NVDA 30-day ATM IV averaged 45% over past 24 months. 30-delta calls yielded 2.1-2.8% monthly premium.", + "contributors": ["muffin"], + "references": [ + { "type": "support", "target": "MUFFIN-P0101" } + ] + } + ], + + "claims": [ + { + "local_id": "MUFFIN-C0101", + "label": "Income mandate resolved", + "content": "The income mandate objection is resolved via options overlay. Remaining concerns are execution timing and concentration—both manageable.", + "contributors": ["muffin"], + "references": [ + { "type": "depend", "target": "MUFFIN-P0101" }, + { "type": "depend", "target": "MUFFIN-E0101" } + ] + } + ], + + "moves": [ + { "expert": "muffin", "type": "bridge", "targets": ["P0003", "R0001"], "context": "Reconciling concentration and collar" }, + { "expert": "donut", "type": "defend", "target": "R0001", "context": "Liquidity supports execution" } + ], + + "tension_updates": [ + { "id": "T0001", "status": "addressed", "by": ["donut"], "via": "DONUT-R0101" }, + { "id": "T0002", "status": "resolved", "by": ["cupcake"], "via": "CUPCAKE-P0101" } + ] +} +``` + +**Local ID format:** `{UPPER(expert)}-{TYPE}{round:02d}{seq:02d}` +- Perspectives: `MUFFIN-P0101`, `CUPCAKE-P0102` +- Proposals: `DONUT-R0101`, `MUFFIN-R0103` +- Tensions: `CROISSANT-T0101`, `SCONE-T0201` +- Evidence: `MUFFIN-E0101`, `DONUT-E0102` +- Claims: `MUFFIN-C0101`, `CUPCAKE-C0102` + +**Resolution:** +- MCP resolves local IDs → global IDs before storing +- **Input**: Links can reference local IDs (same batch) or global IDs (prior rounds) +- **Storage**: All links stored with global IDs only (MCP resolves local refs) +- Return includes mapping: `local_id` → `global_id` + +```json +``` + +**MCP resolves local IDs, assigns global IDs, returns mapping:** + +Note: Local seq is expert-local, global seq is dialogue-global. Three experts each writing their "first" perspective (local `01`) get global `01`, `02`, `03`: + +```json +{ + "round": 1, + "id_mapping": { + "MUFFIN-P0101": "P0101", // Muffin's 1st → global 1st + "CUPCAKE-P0101": "P0102", // Cupcake's 1st → global 2nd + "SCONE-P0101": "P0103", // Scone's 1st → global 3rd + "DONUT-R0101": "R0101", + "CROISSANT-T0101": "T0101", + "MUFFIN-E0101": "E0101", + "MUFFIN-C0101": "C0101" + }, + "perspectives": [ + { "local_id": "MUFFIN-P0101", "id": "P0101", "label": "Options viability confirmed" }, + { "local_id": "CUPCAKE-P0101", "id": "P0102", "label": "Concentration risk mitigated" }, + { "local_id": "SCONE-P0101", "id": "P0103", "label": "Execution timeline concern" } + ], + "recommendations": [ + { "local_id": "DONUT-R0101", "id": "R0101", "label": "Amended collar structure" } + ], + "tensions": [ + { "local_id": "CROISSANT-T0101", "id": "T0101", "label": "Execution timing" } + ], + "evidence": [ + { "local_id": "MUFFIN-E0101", "id": "E0101", "label": "Historical options premium data" } + ], + "claims": [ + { "local_id": "MUFFIN-C0101", "id": "C0101", "label": "Income mandate resolved" } + ], + "tension_updates": [ + { "id": "T0001", "status": "addressed", "via": "R0101" }, + { "id": "T0002", "status": "resolved", "via": "P0102" } + ] +} +``` + +All references stored with resolved global IDs. Note that local seq ≠ global seq: +- Local `MUFFIN-P0101` = Muffin's 1st perspective in round 1 (expert-local numbering) +- Global `P0103` = 3rd perspective registered in round 1 (dialogue-global numbering) + +The `id_mapping` in the response tells the Judge exactly which local ID became which global ID. + +The Judge receives: +- Log what was registered +- Reference new IDs in subsequent operations +- Build the scoreboard with correct global IDs + +This replaces multiple individual calls with a single atomic operation. + +**Export tool parameters:** + +```json +{ + "dialogue_id": "nvidia-decision", + "output_path": "/path/to/dialogues/nvidia-decision.json" +} +``` + +**Returns:** + +```json +{ + "status": "success", + "path": "/path/to/dialogues/nvidia-decision.json", + "stats": { + "rounds": 3, + "experts": 12, + "perspectives": 24, + "recommendations": 8, + "tensions": 12, + "evidence": 6, + "claims": 4, + "totalAlignment": 423 + }, + "warnings": [ + { "type": "missing_score", "expert": "scone", "round": 2, "message": "Expert in panel but no score registered" } + ] +} +``` + +### Error Handling + +**MCP validates all data before database operations.** SQLite CHECK constraint errors are unhelpful ("CHECK constraint failed"), so the MCP layer must provide actionable feedback. + +**Error response format:** + +```json +{ + "status": "error", + "error_code": "invalid_ref_target", + "field": "ref_type", + "value": "resolve", + "constraint": "semantic", + "message": "ref_type 'resolve' can only target Tensions (T), but target_type is 'P'", + "context": { + "source_id": "P0101", + "target_id": "P0001", + "target_type": "P" + }, + "valid_options": ["T"], + "suggestion": "Use 'support' or 'oppose' for Perspective targets, or change target to a Tension ID" +} +``` + +**Error codes and validation rules:** + +| Error Code | Constraint | Trigger | Message Template | +|------------|------------|---------|------------------| +| `invalid_entity_type` | Type enum | `source_type` or `target_type` not in (P, R, T, E, C) | `{field} must be one of: P, R, T, E, C (got '{value}')` | +| `invalid_ref_type` | Ref enum | `ref_type` not in valid set | `ref_type must be one of: support, oppose, refine, address, resolve, reopen, question, depend (got '{value}')` | +| `type_id_mismatch` | Type consistency | `source_type` doesn't match `source_id` prefix | `{type}_type '{type_value}' does not match {type}_id '{id}' (expected prefix '{expected}')` | +| `invalid_ref_target` | Semantic | `resolve`/`reopen`/`address` targeting non-Tension | `ref_type '{ref}' can only target Tensions (T), but target_type is '{actual}'` | +| `refine_type_mismatch` | Semantic | `refine` with different source/target types | `ref_type 'refine' requires same source and target type (got {source}→{target})` | +| `target_not_found` | Referential | Referenced ID doesn't exist | `target_id '{id}' not found in dialogue '{dialogue_id}'` | +| `invalid_status_transition` | Lifecycle | Invalid state transition | `Cannot transition {entity} from '{from}' to '{to}' (valid transitions: {valid})` | + +**Validation order:** + +1. **Type enums** — Check `source_type`, `target_type`, `ref_type` are valid values +2. **Type consistency** — Check ID prefixes match declared types +3. **Referential integrity** — Check target IDs exist in the dialogue +4. **Semantic constraints** — Check relationship type is valid for target type +5. **Lifecycle rules** — Check status transitions are valid + +**Partial success handling:** + +For bulk operations (`blue_dialogue_round_register`), the MCP uses atomic transactions: +- **All-or-nothing**: If any item fails validation, the entire batch is rejected +- **Detailed errors**: Response includes validation errors for ALL failed items, not just the first + +```json +{ + "status": "error", + "error_code": "batch_validation_failed", + "message": "3 items failed validation", + "errors": [ + { + "item_type": "reference", + "source_id": "P0101", + "error_code": "invalid_ref_target", + "message": "ref_type 'resolve' can only target Tensions..." + }, + { + "item_type": "perspective", + "local_id": "MUFFIN-P0102", + "error_code": "type_id_mismatch", + "message": "Perspective ID must start with 'P', got 'MUFFIN-P0102'" + } + ], + "suggestion": "Fix all errors and resubmit the entire batch" +} +``` + +**Judge recovery pattern:** + +When the Judge receives a validation error: +1. Parse the `error_code` and `suggestion` +2. Identify the problematic items +3. Correct the data based on `valid_options` or `suggestion` +4. Resubmit the entire batch (for bulk operations) + +The structured error format ensures the Judge can programmatically understand and fix issues without human intervention. + +### Agent Context Model + +**MCP provides data; Judge builds prompts; Agents receive prompts directly.** + +The Judge calls `blue_dialogue_round_context` once to get structured data for **all panel experts**: + +```json +// Request +{ + "dialogue_id": "nvidia-decision", + "round": 1 +} + +// Response +{ + "dialogue": { + "id": "nvidia-decision", + "title": "NVIDIA Investment Analysis", + "question": "Should Acme Trust swap its NVAI position for NVDA shares?", + "status": "open", + "current_round": 1, + "total_alignment": 117, + "background": { + "subject": "Acme Family Trust", + "description": "$50M multi-generational family trust", + "constraints": { + "income_mandate": "4% annual distribution to beneficiaries", + "risk_tolerance": "Moderate (fiduciary duty)", + "time_horizon": "20+ years", + "current_allocation": "60% equities, 30% fixed income, 10% alternatives" + }, + "situation": "Trust holds $2.1M in NVAI (NVIDIA preferred, 3.2% yield). Proposal: swap NVAI for NVDA (common, 0% dividend). NVDA +180% YTD. Key tension: NVDA pays no dividend, conflicting with 4% income mandate." + } + }, + + // Calibration (RFC 0054) — only present if calibrated: true + "calibration": { + "ethos_id": "ethos-nvidia-001", + "domain": "Fiduciary Investment Analysis", + "rules": [ + { "seq": 1, "type": "principle", "label": "Evidence must be citable", "priority": 100 }, + { "seq": 2, "type": "tenet", "label": "Fiduciary duty supersedes growth", "priority": 1000 }, + { "seq": 3, "type": "constraint", "label": "4% annual income required", "priority": 500 } + ], + "prompt_injection": "## Calibration: Fiduciary Investment Analysis\n\n..." + }, + + "prior_rounds": [ + { + "round": 0, + "score": 117, + "expert_contributions": [ + { + "expert": "muffin", + "role": "Value Analyst", + "perspectives": [ + { "id": "P0001", "label": "Income mandate mismatch", "status": "open", "content": "NVIDIA's zero dividend directly conflicts with the trust's 4% income requirement..." } + ], + "tensions_raised": ["T0001"], + "recommendations": [] + }, + { + "expert": "cupcake", + "role": "Risk Manager", + "perspectives": [ + { "id": "P0002", "label": "Concentration risk", "status": "open", "content": "Adding NVDA increases semiconductor exposure to 23% of portfolio..." } + ], + "tensions_raised": ["T0002"], + "recommendations": [] + }, + { + "expert": "donut", + "role": "Options Strategist", + "perspectives": [ + { "id": "P0003", "label": "Options overlay opportunity", "status": "open", "content": "A covered call strategy on NVDA could generate 18-34% annualized income..." } + ], + "tensions_raised": [], + "recommendations": [ + { "id": "R0001", "label": "Income Collar Structure", "content": "Strike Selection Framework...", "parameters": { "covered_call_delta": "0.20-0.25" } } + ] + } + ], + "tensions": [ + { "id": "T0001", "label": "Growth vs income", "expert": "muffin", "status": "open", "description": "NVIDIA's zero dividend conflicts with 4% income mandate" }, + { "id": "T0002", "label": "Concentration risk", "expert": "cupcake", "status": "addressed", "description": "Semiconductor exposure would reach 23%" } + ], + "judge_synthesis": "11-1 split: majority concerns about income mandate..." + } + ], + + "active_tensions": [ + { "id": "T0001", "label": "Growth vs income", "status": "open" }, + { "id": "T0003", "label": "Volatility drag", "status": "open" } + ], + + // Per-expert data keyed by slug + "experts": { + "muffin": { + "slug": "muffin", + "role": "Value Analyst", + "tier": "Core", + "source": "retained", + "focus": "Intrinsic value, margin of safety", + "description": "You evaluate investments through the lens of intrinsic value...", + "your_score": 12, + "round_context": "In round 0, you raised T0001 (income mandate mismatch) which remains open. Donut proposed an options overlay that may address your concern." + }, + "cupcake": { + "slug": "cupcake", + "role": "Risk Manager", + "tier": "Core", + "source": "retained", + "focus": "Downside scenarios, tail events", + "description": "You identify and quantify risks...", + "your_score": 8, + "round_context": "Your T0002 (concentration risk) was addressed last round..." + }, + "eclair": { + "slug": "eclair", + "role": "Tax Strategist", + "tier": "Adjacent", + "source": "pool", // From initial pool, not previously active - Judge writes context brief + "focus": "Tax implications, harvest strategies", + "description": "You analyze tax consequences...", + "your_score": 0, + "round_context": null + }, + "scone": { + "slug": "scone", + "role": "Supply Chain Analyst", + "tier": "Wildcard", + "source": "created", // Invented by Judge - Judge writes context brief + mandate + "focus": "Supply chain dependencies, geopolitical risk", + "description": "You analyze supply chain vulnerabilities...", + "your_score": 0, + "round_context": null, + "creation_reason": "Address T0003 supply chain concerns" + } + } +} +``` + +**One call returns context for entire panel.** Judge builds prompts in parallel from shared + expert-specific data. + +**MCP provides structured data. Judge adds value through:** +- Emphasis and framing based on dialogue dynamics +- Custom `round_context` for each expert's situation +- Context briefs for fresh experts (constructed from structured data) + +**For fresh experts** (pool or created): +- Judge writes a context brief from `prior_rounds` data, highlighting relevant prior discussion +- `prior_rounds` contains **full content** from all experts in all prior rounds (same as retained experts) +- The brief orients them; the full content lets them engage deeply +- `created` experts additionally receive a mandate explaining why they were invented + +**Content availability guarantee:** +- All agents receive structured `perspectives`, `recommendations`, `tensions`, `evidence`, `claims` with full `content` field +- All IDs use global format (e.g., `P0001`, `R0001`, `T0001`) — no local ID confusion +- No content is hidden or summarized-only +- Fresh experts and retained experts see the same prior round data + +*Note: Raw markdown responses are stored in `experts.raw_content` JSON for debugging but not included in agent context to avoid local/global ID confusion.* + +### Prompt Assembly (Judge Responsibility) + +The Judge fetches context in bulk and builds prompts in parallel: + +``` +1. FETCH (single call) + └─ Judge calls blue_dialogue_round_context(dialogue_id, round) + └─ MCP returns context for ALL panel experts + +2. BUILD + WRITE (parallel for each expert) + └─ Judge synthesizes markdown prompt from shared + expert data + └─ Judge writes prompt-{expert}.md and context-{expert}.json + +3. SPAWN (parallel - one message, multiple Task calls) + └─ Judge spawns ALL agents with prompt + alignment-expert skill + +4. RESPOND (parallel - agents run concurrently) + └─ Each agent writes response-{expert}.md +``` + +**Why Judge builds prompts (not MCP):** +- Judge can emphasize specific tensions based on dialogue dynamics +- Judge can customize `round_context` per expert's situation +- Judge can frame fresh expert mandates appropriately +- MCP stays focused on data access, not LLM prompt engineering + +**Parallelization benefits:** +- Single MCP call instead of N calls (reduces latency) +- Parallel file writes (no serialization) +- Parallel agent spawning (all in one message) +- Agents run concurrently (no first-mover advantage) + +**Filesystem artifacts (for human debugging):** + +| File | Written by | Purpose | +|------|------------|---------| +| `prompt-{expert}.md` | Judge | Exact markdown prompt agent received | +| `context-{expert}.json` | Judge | Structured JSON data used to build prompt | +| `response-{expert}.md` | Agent | Agent's deliberation response | + +**Prompt format:** + +```markdown +# Dialogue: NVIDIA Investment Analysis +**Question:** Should Acme Trust swap its NVAI position for NVDA shares? +**Round:** 1 of ? | **Status:** open | **Total ALIGNMENT:** 117 + +--- + +## Background + +**Acme Family Trust** is a $50M multi-generational family trust. + +| Constraint | Requirement | +|------------|-------------| +| Income mandate | 4% annual distribution to beneficiaries | +| Risk tolerance | Moderate (fiduciary duty) | +| Time horizon | 20+ years | +| Current allocation | 60% equities, 30% fixed income, 10% alternatives | + +**Current situation:** +- Trust holds $2.1M in NVAI (NVIDIA preferred, 3.2% yield) +- Proposal: Swap NVAI → NVDA (common shares, 0% dividend) +- NVDA has appreciated 180% YTD; NVAI underperformed +- Key tension: NVDA pays no dividend, conflicting with 4% income mandate + +--- + +## Your Role + +**Muffin** 🧁 | Value Analyst | Core +Focus: Intrinsic value, margin of safety +Your score: 12 | Source: retained + +You evaluate investments through the lens of intrinsic value, seeking companies +trading below fair value with adequate margin of safety. You are skeptical of +momentum-driven narratives and prioritize cash flow analysis, balance sheet +strength, and sustainable competitive advantages. + +### Your Task This Round + +In round 0, you raised T0001 (income mandate mismatch) which remains open. Donut +proposed an options overlay that may address your concern. Your task this round: +evaluate whether the options strategy adequately resolves the income gap, or +articulate why it falls short. + +--- + +## Prior Rounds + +### Round 0 — Opening Arguments (Score: 117) + +#### Muffin (You) — Value Analyst +[P0001: Income mandate mismatch] (muffin) +NVIDIA's zero dividend directly conflicts with the trust's 4% income requirement... + +[TENSION T0001: Growth vs income] +The fundamental tension between growth exposure and income mandate. + +--- + +#### Cupcake — Risk Manager +[P0002: Concentration risk] (cupcake) +Adding NVDA increases semiconductor exposure to 23% of portfolio... + +[TENSION T0002: Concentration risk] +Portfolio concentration in semiconductors exceeds policy limits. + +--- + +#### Donut — Options Strategist +[P0003: Options overlay opportunity] (donut) +A covered call strategy on NVDA could generate 18-34% annualized income... + +[R0001: Income Collar Structure] (donut) +Strike Selection Framework: +| Parameter | Value | Rationale | +|-----------|-------|-----------| +| Covered call delta | 0.20-0.25 | Balance premium vs upside | +| Protective put delta | -0.15 | Tail risk protection | +| DTE | 30-45 | Optimal theta decay | + +--- + +### Judge Synthesis — Round 0 +11-1 split: majority concerns about income mandate, but Donut's options overlay +opens a potential path forward. Key tensions T0001 and T0002 require resolution. + +--- + +## Active Tensions + +| ID | Description | Origin | Status | Your Involvement | +|----|-------------|--------|--------|------------------| +| T0001 | Growth vs income mandate | Muffin | open | originator | +| T0002 | Concentration risk | Cupcake | addressed | — | +| T0003 | Volatility drag on returns | Scone | open | — | + +--- + +## Instructions + +You are Muffin 🧁, a Value Analyst participating in round 1 of this ALIGNMENT dialogue. + +Your contribution is scored on PRECISION, not volume. One sharp insight beats ten paragraphs. + +Structure your response using the markers from your skill (P, R, T, E, C for perspectives, recommendations, tensions, evidence, claims; plus cross-references and moves). Use your expert slug in local IDs: `MUFFIN-P0101`, `MUFFIN-R0101`, `MUFFIN-T0101`, etc. + +Focus on: What has changed since round 0? Which tensions can you help resolve? +``` + +### Alignment Expert Skill + +Agents are spawned with the `alignment-expert` skill, which contains **static** marker syntax reference. This avoids repeating ~800 tokens of marker documentation in every prompt. + +**Skill file:** `~/.claude/skills/alignment-expert/SKILL.md` + +```markdown +# Alignment Expert + +You are an expert participating in an ALIGNMENT dialogue. Structure your +response using these markers. + +## Local ID Format + +Use your expert slug (UPPERCASE) with type prefix and 4-digit round+seq: +- `{EXPERT}-P{round:02d}{seq:02d}` — Perspective (e.g., MUFFIN-P0101) +- `{EXPERT}-R{round:02d}{seq:02d}` — Recommendation (e.g., MUFFIN-R0101) +- `{EXPERT}-T{round:02d}{seq:02d}` — Tension (e.g., MUFFIN-T0101) +- `{EXPERT}-E{round:02d}{seq:02d}` — Evidence (e.g., MUFFIN-E0101) +- `{EXPERT}-C{round:02d}{seq:02d}` — Claim (e.g., MUFFIN-C0101) + +## First-Class Entities + +| Marker | Purpose | +|--------|---------| +| `[{local_id}: label]` | Type encoded in ID prefix (P, R, T, E, C) | + +Examples: +- `[MUFFIN-P0101: Income mandate mismatch]` — Perspective +- `[DONUT-R0101: Options collar structure]` — Recommendation +- `[MUFFIN-T0101: Growth vs income]` — Tension +- `[MUFFIN-E0101: Historical IV data]` — Evidence +- `[MUFFIN-C0101: Income gap bridgeable]` — Claim + +## Cross-References + +Link to prior items (global IDs) or same-round items (local IDs): + +| Marker | Purpose | +|--------|---------| +| `[RE:SUPPORT {id}]` | Endorse referenced item | +| `[RE:OPPOSE {id}]` | Challenge referenced item | +| `[RE:REFINE {id}]` | Build on and improve (same type only) | +| `[RE:ADDRESS {id}]` | Propose solution to tension | +| `[RE:RESOLVE {id}]` | Claim tension is fully resolved | +| `[RE:REOPEN {id}]` | Argue resolved tension needs revisiting | +| `[RE:QUESTION {id}]` | Ask for clarification | +| `[RE:DEPEND {id}]` | This item depends on referenced item | + +**Constraints:** +- `RE:RESOLVE`, `RE:REOPEN`, `RE:ADDRESS` — must target Tensions (T) +- `RE:REFINE` — must target same entity type (P→P, R→R, etc.) + +## Dialogue Moves + +| Marker | Purpose | +|--------|---------| +| `[MOVE:DEFEND {id}]` | Strengthen case for item | +| `[MOVE:CHALLENGE {id}]` | Question assumptions | +| `[MOVE:BRIDGE {id1} {id2}]` | Synthesize into common ground | +| `[MOVE:REQUEST {topic}]` | Ask panel for input | +| `[MOVE:CONCEDE {id}]` | Withdraw position in favor of item | +| `[MOVE:CONVERGE]` | Signal readiness to conclude | + +## Verdicts + +| Marker | Purpose | +|--------|---------| +| `[DISSENT]` | Formal objection with reasoning | +| `[MINORITY VERDICT: label]` | Alternative recommendation from coalition | + +## Output Rules + +1. Write response to: `{output_dir}/round-{N}/response-{expert_slug}.md` +2. Return structured summary to Judge (perspectives, recommendations, tensions, evidence, claims, refs) +3. One sharp insight beats ten paragraphs — PRECISION over volume +``` + +**Judge spawns agents with:** + +```python +spawn_agent( + skill="alignment-expert", # Static marker syntax + prompt=full_markdown_prompt # Dynamic context (Judge-built) +) +``` + +**Separation of concerns:** + +| Content | Source | Rationale | +|---------|--------|-----------| +| Marker syntax | Skill | Static, same for all agents, ~800 tokens | +| Dialogue background | Prompt | Dynamic, dialogue-specific | +| Expert role/mandate | Prompt | Dynamic, agent-specific | +| Prior rounds | Prompt | Dynamic, round-specific | +| Active tensions | Prompt | Dynamic, changes each round | +| Instructions | Prompt | Dynamic, may vary by expert source | + +**Why Judge passes prompt directly (not file path):** +- Simpler — no file read step for agent +- Fewer failure modes — no file access issues +- Prompt is already in Judge's memory +- Filesystem write is for human debugging only + +### Dynamic Expert Creation + +The Judge can **create new experts at any point** before a round to address emerging needs: + +**MCP tool:** `blue_dialogue_expert_create` + +```json +{ + "dialogue_id": "nvidia-decision", + "expert_slug": "palmier", + "role": "Geopolitical Risk Analyst", + "description": "You analyze investments through the lens of geopolitical risk, focusing on supply chain vulnerabilities, regulatory exposure, and country-specific risks. You are particularly attentive to concentration risk in politically sensitive regions.", + "focus": "Taiwan semiconductor concentration, export controls", + "tier": "Adjacent", + "reason": "T0003 (supply chain concentration) requires specialized geopolitical expertise not present in current panel" +} +``` + +**When to create experts:** +- Existing panel lacks expertise to resolve a specific tension +- New deliberation focus emerges that needs dedicated attention +- Wildcard injection to challenge emerging consensus +- Domain shift mid-dialogue (e.g., legal question surfaces) + +**What happens:** +1. Judge calls `blue_dialogue_expert_create` before the round +2. MCP inserts expert into `experts` table with `source: "created"` +3. Expert is included in next `blue_dialogue_evolve_panel` call +4. Judge constructs context brief from `blue_dialogue_round_context` structured data + +**Created experts receive (assembled by Judge):** +- Full `prior_rounds` content (same as retained experts) +- Judge-written context brief summarizing relevant discussion and why they were brought in +- `round_context` focused on their specific mandate + +**Example context brief for created expert:** + +```markdown +## Context Brief (You are joining in Round 2) + +You were brought in to address **T0003: Supply chain concentration risk**. + +--- + +### The Dialogue Question + +**Should Acme Family Trust swap its NVAI position for NVDA shares?** + +### Background: Acme Family Trust + +Acme Family Trust is a $50M multi-generational family trust with the following +constraints: + +| Constraint | Requirement | +|------------|-------------| +| **Income mandate** | 4% annual distribution to beneficiaries | +| **Risk tolerance** | Moderate (fiduciary duty to preserve capital) | +| **Time horizon** | 20+ years (multi-generational) | +| **Current allocation** | 60% equities, 30% fixed income, 10% alternatives | + +**Current situation:** +- Trust holds $2.1M in NVAI (NVIDIA preferred shares, 3.2% yield) +- Proposal: Swap NVAI for NVDA (common shares, 0% dividend) +- NVDA has appreciated 180% YTD; NVAI has underperformed +- Trustee believes NVDA growth potential outweighs income loss + +**Key tension:** NVDA pays no dividend, conflicting with 4% income mandate. + +--- + +### Why You're Here + +After two rounds of deliberation, the income mandate concerns (T0001) have been +resolved via an options overlay strategy. However, a critical tension remains +unaddressed: **geographic concentration risk in semiconductor supply chain**. + +No current panelist has geopolitical risk expertise, so you were created to +provide this specialized perspective. + +### Your Mandate + +1. Evaluate the geopolitical risk of Taiwan semiconductor concentration +2. Quantify probability and impact scenarios for supply disruption +3. Propose risk mitigation strategies if viable +4. If risks are unacceptable, strengthen the case for rejection + +--- + +### Key Context: The Tension You're Addressing + +**T0003: Supply chain concentration risk** (raised by Cupcake, Round 0) +> "NVIDIA's 87% dependency on TSMC Taiwan fabrication represents unhedgeable +> tail risk. A Taiwan Strait crisis would eliminate access to advanced chips +> with no alternative supplier capable of 3nm production." + +### Relevant Prior Perspectives + +**P0003** (Cupcake, Risk Manager, Round 0): +> "Taiwan exposure represents unhedgeable tail risk. Unlike financial risks +> that can be managed through derivatives, geopolitical supply disruption has +> no market hedge. The 87% TSMC concentration means a single point of failure +> for NVIDIA's entire product line. Historical precedent: the 2021 chip +> shortage caused 18-month delivery delays even without military conflict." + +**P0005** (Scone, Supply Chain Analyst, Round 1): +> "TSMC has no viable alternative for 3nm production. Intel Foundry Services +> won't reach parity until 2027 at earliest. Samsung's 3nm yields remain +> below 60%. NVIDIA cannot diversify its fab dependency in the investment +> horizon we're considering. The concentration is structural, not strategic." + +**P0008** (Donut, Options Strategist, Round 1): +> "Geopolitical risk cannot be hedged with options. While we can manage +> volatility and income through derivatives, there is no instrument that +> protects against a binary supply disruption event. This is outside my +> domain—we need specialized geopolitical analysis." + +--- + +### Dialogue Progress + +- **Round 0 (Score: 117):** Panel identified income mandate conflict and + concentration risks. 11-1 against full position. +- **Round 1 (Score: 45):** Options overlay resolved income concerns. T0001 + addressed. T0003 flagged as requiring specialized expertise. +- **Current ALIGNMENT:** 162 (velocity decreasing, approaching convergence + pending T0003 resolution) + +### What the Panel Needs From You + +The panel is close to convergence on a conditional approval, but T0003 blocks +final consensus. Your analysis will determine whether: +- The geopolitical risk is acceptable with conditions → conditional approval +- The risk is unacceptable → strengthen rejection case +- The risk can be mitigated → propose specific measures +``` + +**Context brief requirements (Judge responsibility):** + +The context brief the Judge writes for fresh experts (pool or created) MUST include: + +1. **The dialogue question** — What is being decided? +2. **Foundational context** — Background, constraints, current situation (everything an expert needs to understand the problem domain) +3. **Why they're here** — What gap they fill or tension they address +4. **Their mandate** — Specific responsibilities and expected outputs +5. **Relevant prior work** — Key perspectives, recommendations, tensions, evidence, claims related to their mandate +6. **Dialogue progress** — Round summaries, current ALIGNMENT, velocity + +Fresh experts must be **fully self-sufficient** after reading their context. They should never need to ask "what is this dialogue about?" or "what are the constraints?" + +*Note: Fresh experts (pool or created) also receive the full `prior_rounds` data (same as retained experts), so they can review all expert contributions in detail. The context brief orients them to the dialogue and highlights the most relevant prior work.* + +**Expert sources in panel evolution:** + +| Source | Meaning | Context | +|--------|---------|---------| +| `retained` | Continuing from prior round | Full history, their contributions highlighted | +| `pool` | Drawn from initial expert pool (not previously active) | Full history + Judge-written brief | +| `created` | Invented by Judge for this dialogue (not in pool) | Full history + Judge-written brief + mandate | + +### Judge Workflow (for skill documentation) + +**Round execution (maximally parallelized):** + +``` +0. EVOLVE PANEL (Judge discretion) + └─ Judge reviews prior round results, open tensions, dialogue progress + └─ Judge decides panel composition for this round: + - Retain high-performing experts + - Draw from pool to address gaps + - Create new experts for specialized needs + └─ Judge calls blue_dialogue_evolve_panel(dialogue_id, round, panel) + → MCP records panel composition with source for each expert + +1. FETCH CONTEXT (single bulk call) + └─ Judge calls blue_dialogue_round_context(dialogue_id, round) + → MCP returns context for ALL panel experts in one response + → Shared data: dialogue, background, prior_rounds, active_tensions + → Per-expert data: role, focus, source, round_context + +2. BUILD PROMPTS + WRITE FILES (parallel) + └─ For fresh experts (pool or created): Judge writes context brief from structured data + └─ For each expert IN PARALLEL: + └─ Judge synthesizes markdown prompt from shared + expert data + └─ Judge writes prompt-{expert}.md (parallel file writes) + └─ Judge writes context-{expert}.json (parallel file writes) + +3. SPAWN AGENTS (parallel) + └─ Judge spawns ALL agents in ONE message with multiple Task tool calls: + - skill: alignment-expert (static marker syntax) + - prompt: full markdown content (from step 2) + └─ Agents deliberate using prompt + skill + └─ Agents write responses with LOCAL IDs: [MUFFIN-P0101] + └─ Each agent writes to: {output_dir}/round-{N}/response-{expert_slug}.md + └─ Each agent returns summary to Judge + +4. COLLECT AGENT OUTPUTS + └─ Judge receives agent return values (summaries of what each contributed) + └─ Judge reads full responses from {output_dir}/round-{N}/response-*.md + └─ Judge reviews all contributions, identifies: + - New perspectives (with local IDs like MUFFIN-P0101) + - New proposals (with local IDs like DONUT-R0101) + - New tensions (with local IDs like CUPCAKE-T0101) + - Tension updates (addressed, resolved) + - Cross-references between experts + +5. SCORE AND REGISTER + └─ Judge scores each expert's contribution (ALIGNMENT dimensions) + └─ Judge synthesizes similar contributions (multiple experts → one record) + └─ Judge calls blue_dialogue_round_register({ + round, score, expert_scores, + perspectives, recommendations, tensions, evidence, claims, + tension_updates + }) + → MCP assigns global IDs (P0101, R0101, T0101) + → Returns ID mapping for Judge's records + +6. CHECK CONVERGENCE + └─ If converging: blue_dialogue_verdict_register(...) after step 5 + └─ If continuing: goto step 0 for next round (panel evolution) +``` + +**Agent output format:** + +Each agent writes a markdown file with structured markers: +```markdown +# Muffin - Value Analyst (Round 1) + +[MUFFIN-P0101: Options viability confirmed] +The 30-delta covered call strategy can generate 18-34% annualized income, +effectively bridging the income mandate gap... + +[RE: DONUT-R0001] +The collar structure addresses my T0001 concern. I support adoption with +the 45 DTE modification. + +[MUFFIN-T0102: Execution timing risk] +Post-refinancing window creates a 60-90 day constraint that may conflict +with optimal entry points... +``` + +**Agent return value:** + +Agents return a structured summary to the Judge: +```json +{ + "expert_slug": "muffin", + "round": 1, + "response_path": "/tmp/blue-dialogue/nvidia-decision/round-1/response-muffin.md", + "summary": { + "perspectives": ["MUFFIN-P0101"], + "recommendations": [], + "tensions_raised": ["MUFFIN-T0101"], + "evidence": ["MUFFIN-E0101"], + "claims": ["MUFFIN-C0101"], + "references": [ + { "type": "refine", "from": "MUFFIN-P0101", "target": "P0001" }, + { "type": "support", "from": "MUFFIN-P0101", "target": "R0001" }, + { "type": "address", "from": "MUFFIN-P0101", "target": "T0001" }, + { "type": "support", "from": "MUFFIN-E0101", "target": "MUFFIN-P0101" }, + { "type": "depend", "from": "MUFFIN-C0101", "target": "MUFFIN-P0101" } + ], + "moves": [ + { "type": "bridge", "targets": ["P0003", "R0001"] } + ] + } +} +``` + +**Why Judge builds prompts (not MCP or agents):** +- Judge can customize emphasis based on dialogue dynamics +- Judge controls framing for fresh vs retained experts +- Judge writes context_brief with specific mandates for created experts +- MCP stays focused on data access, not prompt engineering + +**Key points for alignment-play skill:** +- Judge fetches data via `blue_dialogue_round_context`, builds prompts +- Judge writes prompts to filesystem for debugging +- Judge spawns agents with full prompt + `alignment-expert` skill +- Agents write local IDs — Judge maps to global IDs during registration +- Use `blue_dialogue_round_register` for bulk operations (faster) + +### Data Registration Model + +**All dialogue data is registered via MCP tools as the dialogue progresses.** The Judge registers data after each round: + +``` +Round 0 completes: + → Judge scores responses + → Judge calls blue_dialogue_round_register with all round data: + - perspectives, recommendations, tensions, evidence, claims + - cross-references (refs) + - tension_updates + - expert_scores + +Round N completes (convergence): + → Judge calls blue_dialogue_round_register (same as every round) + → Judge calls blue_dialogue_verdict_register for majority verdict + → Judge identifies dissenters from final round contributions + → Judge calls blue_dialogue_verdict_register for each minority verdict (on behalf of dissenting experts) +``` + +**Benefits:** +- Export is a simple DB query, no file parsing +- Data is queryable in real-time during dialogue +- Single source of truth (database, not scattered files) +- Files (`.md`) become human-readable artifacts, not data sources + +### Export Tooling: `blue_dialogue_export` + +The MCP tool queries the database and generates a single JSON file: + +``` +blue_dialogue_export(dialogue_id="nvidia-decision", output_path="/path/to/nvidia-decision.json") + → Single file with all dialogue data +``` + +#### Data Sources (all from SQLite) + +| Table | Export Section | +|-------|----------------| +| `dialogues` | Root metadata, status, alignment total | +| `experts` | `experts[]` with `scores` and `raw_content` JSON (per-round) | +| `expert_pool` | `expert_pool` (original pool definition) | +| `rounds` | `rounds[]` metadata | +| `perspectives` | `perspectives[]` with events | +| `proposals` | `proposals[]` with events | +| `tensions` | `tensions[]` with events | +| `evidence` | `evidence[]` with events | +| `claims` | `claims[]` with events | +| `refs` | Embedded in each entity's `references[]` array | +| `moves` | `moves[]` (dialogue moves: defend, challenge, bridge, etc.) | +| `tension_events` | Embedded in tension `events[]` | +| `verdicts` | `verdicts[]` | + +#### Output: Single `dialogue.json` + +```json +{ + "id": "nvidia-decision", + "title": "NVIDIA Investment Decision", + "question": "Should Acme Trust add NVIDIA?", + "date": "2026-02-02", + "status": "converged", + "totalRounds": 3, + "totalAlignment": 423, + + "expert_pool": { + "domain": "Investment Analysis", + "experts": [ + { "role": "Value Analyst", "tier": "Core", "relevance": 0.95 }, + { "role": "Risk Manager", "tier": "Core", "relevance": 0.90 } + ] + }, + + "experts": [ + { + "slug": "muffin", + "role": "Value Analyst", + "tier": "Core", + "source": "pool", + "scores": { "0": 12, "1": 8, "2": 15 }, + "total": 35, + "color": "#3B82F6" + }, + { + "slug": "palmier", + "role": "Geopolitical Risk Analyst", + "tier": "Adjacent", + "source": "created", + "creationReason": "T0003 requires geopolitical expertise", + "scores": { "2": 14 }, + "total": 14, + "color": "#10B981" + } + ], + + "rounds": [ + { + "round": 0, + "title": "Opening Arguments", + "score": 117, + "summary": "11-1 split on full swap vs conditional support", + "experts": { + "muffin": { + "score": 12, + "raw": "[MUFFIN-P0001: Income mandate mismatch]\nNVIDIA's zero dividend...", + "mapping": { "MUFFIN-P0001": "P0001", "MUFFIN-T0001": "T0001" } + }, + "cupcake": { + "score": 10, + "raw": "[CUPCAKE-P0001: Concentration risk]\n...", + "mapping": { "CUPCAKE-P0001": "P0002" } + } + } + }, + { + "round": 1, + "title": "Refinement", + "score": 45, + "summary": "Options overlay gains traction, T0001 addressed", + "experts": { + "muffin": { + "score": 8, + "raw": "[MUFFIN-P0101: Options viability confirmed]\n...", + "mapping": { "MUFFIN-P0101": "P0101" } + } + } + } + ], + + "perspectives": [ + { + "id": "P0001", + "label": "Income mandate mismatch", + "content": "NVIDIA's zero dividend directly conflicts with the trust's 4% income requirement...", + "contributors": ["muffin"], + "round": 0, + "status": "refined", + "references": [], + "events": [ + { "type": "created", "round": 0, "by": ["muffin"] }, + { "type": "refined", "round": 1, "by": ["muffin"], "result": "P0101" } + ] + }, + { + "id": "P0101", + "label": "Options viability confirmed", + "content": "The 30-delta covered call strategy can generate 18-34% annualized income...", + "contributors": ["muffin"], + "round": 1, + "status": "open", + "references": [ + { "type": "refine", "target": "P0001" }, + { "type": "support", "target": "R0001" }, + { "type": "address", "target": "T0001" } + ], + "events": [ + { "type": "created", "round": 1, "by": ["muffin"] } + ] + } + ], + + "recommendations": [ + { + "id": "R0001", + "label": "Income Collar Structure", + "content": "Strike Selection Framework for synthetic income generation...", + "contributors": ["donut"], + "round": 0, + "status": "adopted", + "parameters": { + "covered_call_delta": "0.20-0.25", + "protective_put_delta": "-0.15", + "dte": "30-45" + }, + "references": [ + { "type": "address", "target": "T0001" }, + { "type": "depend", "target": "P0001" } + ], + "adoptedInVerdict": "final", + "events": [ + { "type": "created", "round": 0, "by": ["donut"] }, + { "type": "adopted", "round": 2, "by": ["judge"], "reference": "final" } + ] + } + ], + + "tensions": [ + { + "id": "T0001", + "label": "Growth vs income obligation", + "description": "NVIDIA's zero dividend conflicts with trust's 4% income requirement", + "contributors": ["muffin"], + "round": 0, + "status": "resolved", + "references": [ + { "type": "depend", "target": "P0001" } + ], + "events": [ + { "type": "created", "round": 0, "by": ["muffin"] }, + { "type": "addressed", "round": 1, "by": ["donut"], "reference": "R0001" }, + { "type": "resolved", "round": 2, "by": ["muffin"], "reference": "P0101" } + ] + } + ], + + "evidence": [ + { + "id": "E0101", + "label": "Historical options premium data", + "content": "NVDA 30-day ATM IV averaged 45% over past 24 months. 30-delta calls yielded 2.1-2.8% monthly premium. Premium remained viable during Q4 2022 drawdown.", + "contributors": ["muffin"], + "round": 1, + "status": "confirmed", + "references": [ + { "type": "support", "target": "P0101" } + ], + "events": [ + { "type": "cited", "round": 1, "by": ["muffin"] }, + { "type": "confirmed", "round": 2, "by": ["donut"], "reference": "R0001" } + ] + } + ], + + "claims": [ + { + "id": "C0101", + "label": "Income mandate resolved", + "content": "The income mandate objection is resolved via options overlay. Remaining concerns are execution timing and concentration—both manageable with phased approach.", + "contributors": ["muffin"], + "round": 1, + "status": "adopted", + "references": [ + { "type": "depend", "target": "P0101" }, + { "type": "depend", "target": "E0101" } + ], + "events": [ + { "type": "asserted", "round": 1, "by": ["muffin"] }, + { "type": "supported", "round": 2, "by": ["donut", "cupcake"] }, + { "type": "adopted", "round": 2, "by": ["judge"], "reference": "final" } + ] + } + ], + + "moves": [ + { + "expert": "muffin", + "round": 1, + "type": "bridge", + "targets": ["P0003", "R0001"], + "context": "Reconciling concentration concern with collar proposal via phased entry" + }, + { + "expert": "donut", + "round": 1, + "type": "defend", + "targets": ["R0001"], + "context": "NVDA options liquidity supports execution viability" + }, + { + "expert": "cupcake", + "round": 2, + "type": "concede", + "targets": ["P0003"], + "context": "Phased entry adequately addresses concentration concern" + }, + { + "expert": "muffin", + "round": 2, + "type": "converge", + "targets": [], + "context": "Ready to conclude with conditional approval" + } + ], + + "verdicts": [ + { + "id": "final", + "type": "final", + "round": 2, + "author": null, + "recommendation": "REJECT full swap. APPROVE conditional partial trim.", + "description": "The panel unanimously rejected a full NVAI-to-NVDA swap...", + "conditions": [ + "Execute 60-90 days post-refinancing", + "Implement 30-delta covered calls at 45 DTE" + ], + "tensionsResolved": ["T0001", "T0002"], + "tensionsAccepted": ["T0006"], + "recommendationsAdopted": ["R0001"], + "keyEvidence": ["E0101"], + "keyClaims": ["C0101"], + "vote": "12-0", + "confidence": "unanimous" + } + ] +} +``` + +**Key sections:** + +| Section | Contents | +|---------|----------| +| `expert_pool` | Original pool definition (for reference) | +| `experts[]` | Participating experts with per-round scores | +| `rounds[]` | Round metadata + raw expert content with local→global ID mapping | +| `perspectives[]` | Positions and arguments with `references[]` and events | +| `proposals[]` | Actionable recommendations with parameters, `references[]`, and events | +| `tensions[]` | Conflicts and risks with `references[]`, lifecycle, and events | +| `evidence[]` | Data and precedents with `references[]` and events | +| `claims[]` | Quotable position statements with `references[]` and events | +| `moves[]` | Dialogue moves (defend, challenge, bridge, concede, converge) | +| `verdicts[]` | All verdicts (interim, final, minority, dissent) | + +#### Perspective Status Tracking + +The export tracks perspective lifecycle across rounds: + +| Status | Meaning | +|--------|---------| +| `open` | No engagement yet | +| `refined` | Expert evolved their own perspective | +| `conceded` | Expert withdrew after peer challenge | +| `resolved` | Tension addressed, perspective incorporated | + +#### Verdict Structure + +Dialogues support **multiple verdicts** to capture interim decisions, final conclusions, and minority positions: + +```json +{ + "verdicts": [ + { + "id": "string", // "final", "V01", "minority-esg" + "type": "final", // interim | final | minority | dissent + "round": 3, // Round when issued + "author": "string | null", // Expert slug, or null for Judge + "recommendation": "string", // One-line decision + "description": "string", // 2-3 sentence reasoning + "conditions": ["string"], // Required conditions for approval + "tensions_resolved": ["T0001"], // Tensions addressed by this verdict + "tensions_accepted": ["T0006"], // Tensions acknowledged but not blocking + "recommendations_adopted": ["R0001"], // Recommendations incorporated + "supporting_experts": ["churro"], // For minority/dissent types + "vote": "11-1", // Vote tally + "confidence": "strong" // unanimous | strong | split | contested + } + ] +} +``` + +**Verdict types:** + +| Type | When Used | Author | +|------|-----------|--------| +| `interim` | Mid-dialogue checkpoint, steering decision | Judge | +| `final` | Authoritative conclusion at convergence | Judge | +| `minority` | Structured dissent from expert subset | Lead dissenting expert | +| `dissent` | Single expert's formal objection | Dissenting expert | + +**Registered via MCP** using `blue_dialogue_verdict_register`: +- Judge registers `interim` and `final` verdicts +- Experts can signal dissent to the Judge, who registers `minority` or `dissent` verdicts on their behalf +- All verdicts are immutable once registered (audit trail) + +**Populated from:** +- `[VERDICT]` markers in round summaries (Judge) +- `[DISSENT]` markers in expert responses +- `[MINORITY VERDICT]` markers from expert coalitions +- Resolved/accepted tension status at time of verdict + +#### Global ID Assignment + +Global IDs are assigned at **registration time**, not export time: + +1. Judge calls `blue_dialogue_round_register` with all round data +2. MCP server assigns global `seq` for each entity within `(dialogue_id, round)` +3. Display ID derived: `P{round:02d}{seq:02d}`, `R{round:02d}{seq:02d}`, etc. +4. Export queries database with IDs already assigned + +**No renumbering needed** - the database is the source of truth for all IDs. + +#### Validation & Warnings + +The export validates database consistency: +- Missing expert scores (expert in panel but no score for round) +- Unresolved tensions at convergence +- Orphaned perspectives (no matching expert registration) +- Verdict without required fields + +``` +⚠️ Warnings: + missing_score: scone, round 2 + Expert was in panel but has no score registered + unresolved_tension: T0006 + Dialogue converged with open tension (accepted) + verdict_incomplete: final + Missing tensions_resolved field +``` + +### Two-Phase ID Assignment + +**Phase 1: Agents write with namespaced local IDs** + +Agents use expert-prefixed local IDs in their output: +```markdown +[MUFFIN-P0001: Income mandate mismatch] +[DONUT-R0001: Options collar structure] +[MUFFIN-T0001: Growth vs income] +``` + +These are local to the agent's response. The slug prefix keeps them unique, but sequence numbers overlap across experts (e.g., both MUFFIN-P0101 and CUPCAKE-P0101 exist). + +**Phase 2: Judge registers with global IDs** + +When Judge registers content, the MCP assigns a **global ID**: +- `P0001`, `P0002`, `P0003`... (perspectives, globally sequential per round) +- `R0001`, `R0002`... (proposals, globally sequential per round) +- `T0001`, `T0002`... (tensions, globally sequential per round) +- `E0001`, `E0002`... (evidence, globally sequential per round) +- `C0001`, `C0002`... (claims, globally sequential per round) + +The original namespaced ID is discarded. Expert attribution is stored in the record, not encoded in the ID. + +**Downstream: Global IDs only** + +All references after registration use global IDs: +- Cross-references: `[RE:SUPPORT E0001]`, `[RE:OPPOSE C0003]` +- Tension links: `references: [{"type": "address", "target": "T0001"}]` +- Verdicts: `recommendationsAdopted: ["R0001"]`, `keyEvidence: ["E0001"]` + +### Display ID Formulas + +All IDs use `{round:02d}{seq:02d}` format (4 digits): + +| Entity | Formula | Examples | +|--------|---------|----------| +| Perspective | `P{round:02d}{seq:02d}` | P0001, P0102, P0215 | +| Recommendation | `R{round:02d}{seq:02d}` | R0001, R0102 | +| Tension | `T{round:02d}{seq:02d}` | T0001, T0102 | +| Evidence | `E{round:02d}{seq:02d}` | E0001, E0103 | +| Claim | `C{round:02d}{seq:02d}` | C0001, C0205 | + +The format encodes round implicitly: +- `P0001` = round 0, seq 1 +- `P0102` = round 1, seq 2 +- `P0215` = round 2, seq 15 + +This gives: +- 99 rounds max (00-99) +- 99 items per entity type per round (01-99) +- Human-readable IDs with expert attribution in data, not ID + +### Expert Content Markers + +Experts use these markers in their responses for structured extraction. + +#### First-Class Entities (Global IDs assigned by MCP) + +| Marker | Local ID Example | Description | +|--------|------------------|-------------| +| `[{local_id}: label]` | `MUFFIN-P0101` | Perspective: Position or argument | +| `[{local_id}: label]` | `MUFFIN-R0101` | Recommendation: Actionable proposal | +| `[{local_id}: label]` | `MUFFIN-T0101` | Tension: Conflict, risk, or unresolved issue | +| `[{local_id}: label]` | `MUFFIN-E0101` | Evidence: Data, precedent, or fact | +| `[{local_id}: label]` | `MUFFIN-C0101` | Claim: Quotable position statement | + +Type is encoded in the ID prefix: `P` (perspective), `R` (recommendation), `T` (tension), `E` (evidence), `C` (claim). + +#### Status Lifecycles + +| Entity | Statuses | +|--------|----------| +| Perspective | `open` → `refined` / `conceded` / `merged` | +| Recommendation | `proposed` → `amended` → `adopted` / `rejected` | +| Tension | `open` → `addressed` → `resolved` / `reopened` | +| Evidence | `cited` → `challenged` → `confirmed` / `refuted` | +| Claim | `asserted` → `supported` / `opposed` → `adopted` / `withdrawn` | + +#### Cross-References + +The `[RE: ...]` marker creates typed relationships between contributions: + +| Syntax | Meaning | Example | +|--------|---------|---------| +| `[RE:SUPPORT {id}]` | Endorses the referenced item | `[RE:SUPPORT R0001]` | +| `[RE:OPPOSE {id}]` | Challenges or disagrees with item | `[RE:OPPOSE P0003]` | +| `[RE:REFINE {id}]` | Builds on and improves item | `[RE:REFINE P0001]` | +| `[RE:ADDRESS {id}]` | Proposes solution to tension | `[RE:ADDRESS T0001]` | +| `[RE:RESOLVE {id}]` | Claims tension is fully resolved | `[RE:RESOLVE T0001]` | +| `[RE:REOPEN {id}]` | Argues resolved tension needs revisiting | `[RE:REOPEN T0002]` | +| `[RE:QUESTION {id}]` | Asks for clarification | `[RE:QUESTION R0001]` | +| `[RE:DEPEND {id}]` | This item depends on referenced item | `[RE:DEPEND P0003]` | + +**Semantic constraints (enforced by DB):** + +| ref_type | Valid targets | Constraint | +|----------|---------------|------------| +| `resolve` | T only | Can only resolve a Tension | +| `reopen` | T only | Can only reopen a Tension | +| `address` | T only | Can only address a Tension | +| `refine` | same type | P→P, R→R, C→C, etc. | +| `support` | any | Flexible — endorses any entity | +| `oppose` | any | Flexible — challenges any entity | +| `question` | any | Flexible — asks clarification on any entity | +| `depend` | any | Flexible — logical dependency on any entity | + +**Reference targets:** +- Global IDs for prior rounds: `P0001`, `R0001`, `T0001`, `E0001`, `C0001` +- Local IDs for same-round items: `MUFFIN-P0101`, `DONUT-E0101`, `CUPCAKE-C0101` +- Expert contributions: `@muffin` (references expert's overall position) + +#### Dialogue Moves + +| Marker | Description | +|--------|-------------| +| `[MOVE:DEFEND {id}]` | Strengthens case for referenced item | +| `[MOVE:CHALLENGE {id}]` | Questions assumptions in referenced item | +| `[MOVE:BRIDGE {id1} {id2}]` | Synthesizes two items into common ground | +| `[MOVE:REQUEST {topic}]` | Asks panel for specific input | +| `[MOVE:CONCEDE {id}]` | Withdraws own position in favor of referenced item | +| `[MOVE:CONVERGE]` | Signals readiness to conclude | + +#### Verdicts (Judge and Expert) + +| Marker | Author | Description | +|--------|--------|-------------| +| `[VERDICT:INTERIM]` | Judge | Mid-dialogue checkpoint decision | +| `[VERDICT:FINAL]` | Judge | Authoritative conclusion | +| `[DISSENT]` | Expert | Formal objection with reasoning | +| `[MINORITY VERDICT: label]` | Expert coalition | Alternative recommendation | + +--- + +#### Example: Complete Expert Response + +```markdown +# Muffin - Value Analyst (Round 1) + +[MUFFIN-P0101: Options viability confirmed] +The 30-delta covered call strategy can generate 18-34% annualized income, +effectively bridging the income mandate gap. This addresses my original +concern from P0001. + +[RE:REFINE P0001] +My round 0 perspective on income mandate mismatch evolves: the gap is +bridgeable with derivatives, not insurmountable as I initially framed. + +[RE:SUPPORT R0001] +Donut's collar structure is sound. The 45 DTE recommendation optimizes +theta decay while maintaining flexibility. + +[RE:ADDRESS T0001] +With the options overlay generating 18-34% annualized, the 4% income +mandate can be satisfied. I believe T0001 is addressable pending +execution details. + +[MUFFIN-E0101: Historical options premium data] +- NVDA 30-day ATM IV averaged 45% over past 24 months +- 30-delta calls yielded 2.1-2.8% monthly premium +- Premium remained viable even during Q4 2022 drawdown + +[RE:SUPPORT MUFFIN-P0101] +This data supports my options viability perspective. + +[MUFFIN-T0101: Execution timing constraint] +Post-refinancing window creates 60-90 day delay. Optimal entry may +conflict with covenant restrictions. + +[MOVE:BRIDGE P0003 R0001] +Cupcake's concentration concern and Donut's collar proposal can be +reconciled: phased entry over 6 months limits concentration while +allowing options strategy to scale. + +[MUFFIN-C0101: Income mandate resolved] +The income mandate objection is resolved via options overlay. Remaining +concerns are execution timing and concentration—both manageable with +phased approach. + +[RE:DEPEND MUFFIN-P0101] +[RE:DEPEND MUFFIN-E0101] +``` + +#### Stored Relationships + +Cross-references are stored in the database and exported: + +```json +{ + "id": "P0101", + "label": "Options viability confirmed", + "contributors": ["muffin"], + "references": [ + { "type": "refine", "target": "P0001" }, + { "type": "support", "target": "R0001" }, + { "type": "address", "target": "T0001" } + ], + "moves": [ + { "type": "bridge", "targets": ["P0003", "R0001"] } + ] +} +``` + +**Parsing priority:** The export parser extracts markers in order of appearance, maintaining expert voice while enabling structured analysis. + +## Portability + +This schema is designed for future migration to DynamoDB (see ADR 0017). + +**Single-table pattern:** +``` +PK: dialogue_id +SK: TYPE#subkey + +nvidia-dec | META → dialogue metadata +nvidia-dec | EXPERT#muffin → expert info, total score +nvidia-dec | ROUND#0 → round metadata, score, velocity +nvidia-dec | RSCORE#0#muffin → expert score for round 0 +nvidia-dec | PERSP#0#muffin#1 → perspective (round#expert#seq) +nvidia-dec | REC#0#donut#1 → recommendation (round#expert#seq) +nvidia-dec | CONTRIB#0#muffin#evidence#1 → contribution (non-first-class) +nvidia-dec | TENSION#T0001 → tension +nvidia-dec | TEVENT#T0001#1706900000 → tension event +nvidia-dec | REF#P0101#support#R0001 → cross-reference (source#type#target) +nvidia-dec | VERDICT#final → verdict +nvidia-dec | VERDICT#minority-esg → minority verdict +``` + +**Design constraints for portability:** +1. All queries scoped to single `dialogue_id` (partition key) +2. Composite sort keys encode hierarchy (`TYPE#subkey`) +3. No cross-dialogue JOINs in hot path +4. Judge performs all writes (single writer per dialogue) + +**Why Judge writes all data:** +- Agents run in parallel and could cause write contention +- Judge already reads all agent outputs for scoring +- Single writer eliminates race conditions on `seq` assignment +- SQLite and DynamoDB both benefit from this pattern + +See RFC 0053 for the storage abstraction layer (future work). + +## Calibration (RFC 0054) + +This RFC defines **uncalibrated** dialogues — experts argue freely without domain-specific guardrails. RFC 0054 extends this with **calibrated** dialogues using: + +| Concept | Description | +|---------|-------------| +| **Principle** | Universal truths (inter-domain) | +| **Tenet** | Domain-specific norms ("the way we do things") | +| **Constraint** | Question-specific requirements | +| **Ethos** | Synthesized, conflict-free rule set for a dialogue | + +**Impact on this RFC:** + +1. **Schema**: `dialogues` table gains `calibrated`, `domain_id`, `ethos_id` columns +2. **Context fetch**: `blue_dialogue_round_context` returns `calibration` block with ethos rules +3. **Prompts**: Calibrated dialogues inject ethos into expert prompts +4. **Verdicts**: `ethos_compliance` field tracks compliance and exceptions +5. **Scoring**: Judge may apply calibration modifiers (ethos violations, bonuses) + +**Authoring**: Principles, tenets, and constraints are authored via the `/ethos` skill (see RFC 0054). + +## Implementation + +### Phase 1: Schema +- [ ] Add `dialogues` root table with collision-safe ID generation +- [ ] Add `experts`, `rounds`, `expert_round_scores` tables +- [ ] Add `perspectives`, `tensions`, `tension_events` tables +- [ ] Add `recommendations` table (first-class, links to tensions/perspectives) +- [ ] Add `evidence`, `claims` tables (first-class entities) +- [ ] Add `refs` table for explicit cross-references between entities +- [ ] Add `contributions`, `verdicts` tables +- [ ] Add foreign key constraints to enforce referential integrity +- [ ] Add indices for common query patterns (including refs target/source indices) + +### Phase 2: MCP Tools (Public API) +- [ ] `blue_dialogue_create` - creates dialogue, registers experts from pool +- [ ] `blue_dialogue_round_context` - **bulk fetch** context for all panel experts +- [ ] `blue_dialogue_expert_create` - create new expert mid-dialogue (Judge only) +- [ ] `blue_dialogue_round_register` - **bulk register** all round data in single call +- [ ] `blue_dialogue_verdict_register` - register interim/final/minority verdicts +- [ ] `blue_dialogue_export` - generate JSON export from database + +### Phase 2b: Internal Functions (called by public tools) +- [ ] `perspective_register` - called by `round_register` +- [ ] `recommendation_register` - called by `round_register` +- [ ] `tension_register` - called by `round_register` +- [ ] `tension_update` - called by `round_register` +- [ ] `evidence_register` - called by `round_register` +- [ ] `claim_register` - called by `round_register` +- [ ] `ref_register` - called by `round_register` +- [ ] `recommendation_update` - called by `round_register`, `verdict_register` + +### Phase 2c: Validation Layer +- [ ] Implement MCP-layer validation with structured error responses +- [ ] Implement batch validation (all errors returned, not just first) +- [ ] Add error codes and message templates per constraint type + +### Phase 3: Lifecycle Tracking +- [ ] Implement tension state machine (open → addressed → resolved) +- [ ] Create `tension_events` audit trail +- [ ] Add authority checks for resolution confirmation +- [ ] Support verdict types: interim, final, minority, dissent + +### Phase 4: Export Tooling +- [ ] Implement `blue_dialogue_export` MCP tool +- [ ] Query all data from database (no file parsing) +- [ ] Generate single dialogue.json with all data (perspectives, recommendations, tensions, evidence, claims, verdicts, raw content) +- [ ] Validation and warning reporting +- [ ] Integration with superviber-web demo viewer + +### Phase 5: Skill & Documentation Updates +- [ ] Create `alignment-expert` skill with static marker syntax: + - First-class entity markers (P, R, T, E, C) + - Cross-reference syntax (RE:SUPPORT, RE:OPPOSE, etc.) + - Dialogue move syntax (MOVE:DEFEND, MOVE:BRIDGE, etc.) + - Verdict markers (DISSENT, MINORITY VERDICT) + - Local ID format rules +- [ ] Update `alignment-play` skill with new workflow: + - Judge fetches data via `blue_dialogue_round_context` + - Judge builds prompts, writes to filesystem for debugging + - Judge spawns agents with full prompt + `alignment-expert` skill + - Judge calls `blue_dialogue_round_register` after scoring (bulk registration) + - Two-phase ID system: agents write local IDs, Judge registers global IDs + - Dynamic expert creation via `blue_dialogue_expert_create` +- [ ] Document tool parameters and return values +- [ ] Add examples for common workflows + +### Phase 6: Tooling & Analysis +- [ ] Citation auto-expansion (short form → composite key) +- [ ] Visualization dashboard integration +- [ ] Cross-dialogue analysis queries +- [ ] Real-time dialogue monitoring dashboard + +## Test Plan + +- [ ] **Dialogue ID uniqueness**: Creating dialogue with duplicate title generates suffixed ID +- [ ] **Output directory isolation**: Concurrent dialogues don't overwrite each other's files +- [ ] Composite keys are unique across dialogue +- [ ] Display IDs derived correctly from composite keys +- [ ] Tension lifecycle transitions respect authority rules +- [ ] Reopened tensions preserve original ID and history +- [ ] JSON export backward compatible with existing consumers +- [ ] SQLite indices performant for 100+ perspective dialogues +- [ ] Foreign key constraints prevent orphaned perspectives/tensions +- [ ] **Agent Context**: `blue_dialogue_round_context` returns context for ALL panel experts in one call +- [ ] **Agent Context**: Shared data (dialogue, prior_rounds, tensions) not duplicated per expert +- [ ] **Agent Context**: Per-expert data (role, focus, source, round_context) keyed by slug +- [ ] **Agent Context**: All prompts include `dialogue.background` (subject, constraints, situation) +- [ ] **Agent Context**: Prompts are self-contained — no external knowledge required +- [ ] **Agent Context**: All agents receive structured content with global IDs (no raw_content) +- [ ] **Agent Context**: All agents receive structured perspectives/proposals with full `content` field +- [ ] **Agent Context**: Fresh experts receive same prior_rounds data as retained experts +- [ ] **Agent Context**: Judge writes context brief for fresh experts (pool or created) +- [ ] **Agent Context**: Active tensions include involvement indicator +- [ ] **Expert Creation**: Judge can create new experts mid-dialogue via MCP +- [ ] **Expert Creation**: Created experts have `source: "created"` and `creation_reason` +- [ ] **Expert Creation**: Judge writes context brief with mandate for created experts +- [ ] **Expert Creation**: Context brief includes dialogue question and foundational context +- [ ] **Expert Creation**: Context brief includes constraints, background, current situation +- [ ] **Expert Creation**: Fresh experts are self-sufficient (no "what is this about?" gaps) +- [ ] **Expert Creation**: Created experts can participate starting from any round +- [ ] **Expert Creation**: `first_round` tracks when expert joined +- [ ] **Prompt Assembly**: Judge builds prompts from `blue_dialogue_round_context` data +- [ ] **Prompt Assembly**: Judge writes `prompt-{expert}.md` to disk for debugging +- [ ] **Prompt Assembly**: Judge writes `context-{expert}.json` to disk for debugging +- [ ] **Prompt Assembly**: Markdown prompt includes full content from all prior experts +- [ ] **Prompt Assembly**: Markdown prompt is LLM-friendly (headers, tables, clear structure) +- [ ] **Prompt Assembly**: Judge spawns agents with full prompt + `alignment-expert` skill +- [ ] **Prompt Assembly**: Agents don't need to read files — prompt passed directly +- [ ] **Prompt Assembly**: Agent writes response to `response-{expert}.md` +- [ ] **Skill**: `alignment-expert` skill contains static marker syntax reference +- [ ] **Skill**: Skill loaded once per agent, not repeated in every prompt +- [ ] **Registration**: Perspectives registered with correct composite keys +- [ ] **Proposals**: Proposals have first-class status with global IDs (EXPERT-R0001) +- [ ] **Proposals**: Proposals link to tensions they address +- [ ] **Proposals**: Proposals link to perspectives they build on +- [ ] **Proposals**: Proposal status tracks proposed → adopted/rejected +- [ ] **Proposals**: Adopted proposals linked to verdict +- [ ] **Registration**: Contributions (proposals, evidence, moves) stored with parameters +- [ ] **Registration**: Round completion updates expert scores and dialogue total +- [ ] **Registration**: Tension events create audit trail +- [ ] **Export**: Single dialogue.json contains all sections (experts, rounds, perspectives, recommendations, tensions, evidence, claims, verdicts) +- [ ] **Export**: Global perspective IDs are unique and sequential +- [ ] **Export**: All data comes from database queries (no file parsing) +- [ ] **Export**: Perspective status correctly tracks refinements across rounds +- [ ] **Export**: Proposals include structured parameters from contributions table +- [ ] **Export**: Cross-references build relationship graph between expert contributions +- [ ] **Refs**: Cross-references stored in `refs` table with typed relationships +- [ ] **Refs**: Query "what supports P0001?" uses target index efficiently +- [ ] **Refs**: Query "what does P0101 reference?" uses source index efficiently +- [ ] **Refs**: ref_type constrained to valid types (support, oppose, refine, etc.) +- [ ] **Refs**: Type consistency enforced (source_type='P' requires source_id LIKE 'P%') +- [ ] **Refs**: Semantic constraint: resolve/reopen/address must target Tension (T) +- [ ] **Refs**: Semantic constraint: refine must be same-type (P→P, R→R, etc.) +- [ ] **Refs**: Invalid combo rejected (e.g., `P resolve→ P` fails CHECK) +- [ ] **Errors**: MCP returns structured error with `error_code`, `message`, `suggestion` +- [ ] **Errors**: Type enum violations return `invalid_entity_type` or `invalid_ref_type` +- [ ] **Errors**: Type/ID mismatch returns `type_id_mismatch` with expected prefix +- [ ] **Errors**: Semantic violations return `invalid_ref_target` with valid options +- [ ] **Errors**: Batch operations return all validation errors, not just first +- [ ] **Errors**: Judge can parse error response and correct submission programmatically +- [ ] **Verdicts**: Multiple verdicts per dialogue supported +- [ ] **Verdicts**: Interim verdicts can be registered mid-dialogue +- [ ] **Verdicts**: Minority verdicts capture dissenting coalition +- [ ] **Verdicts**: Verdicts are immutable once registered +- [ ] **Verdicts**: Export includes all verdicts in chronological order + +## Dialogue Summary + +This RFC was designed through a 5-expert alignment dialogue: + +| Expert | Role | Key Contribution | +|--------|------|------------------| +| Cupcake | Traceability Analyst | Composite key design, lifecycle rules | +| Muffin | API Designer | JSON export schema, API contract | +| Brioche | Data Architect | SQLite schema, event audit trail | +| Donut | Skeptic | Challenged assumptions, surfaced lifecycle gap | +| Scone | Performance Engineer | Indexing strategy | +| Eclair | UX Advocate | Human-readable ID advocacy | + +**Key tensions resolved:** +- Prefixed vs Sequential IDs → Storage/display split +- Real-time vs Snapshot tracking → Two-layer architecture +- Merge conflicts → Composite keys +- Lifecycle underspecified → Four-state machine with events + +--- + +*"The blind men now have coordinates. Each can say exactly which part of the elephant they touched."*