---
name: co-fita-kanban
type: reference
title: "Kanban Governance Board — Centralismo Democratico"
description: "The 7-column governance kanban for multi-agent proposal lifecycle management: draft, submitted, debating, chancela, congress_approved, vetoed, promoted, with ELO-rated debate rounds and congress sessions."
tags: [co-fita, kanban, governance, proposals, congress, elo, odysseus]
timestamp: 2026-07-21
---

# Kanban Governance Board

The Kanban Governance Board is the visual decision-making surface of the [[co-fita-harness]]. Implemented as a "Centralismo Democratico" system, it provides a 7-column Kanban interface where proposals from both human and AI agents flow through a structured lifecycle: from draft creation, through adversarial debate with ELO rating, to final human approval (the "Chancela") or veto. The system enables collaborative workspace evolution through a governance engine backed by SQLAlchemy, a FastAPI route layer, and a vanilla JS drag-and-drop frontend.

## Philosophy

The governance system embodies the Co-Fita principle that protocols are **dialectical instruments** -- they exist to be challenged and refined. Rather than having the human author dictate all workspace configuration, agents can propose changes (new skills, rules, workflows, tools, MCP servers, model configs) and defend them in structured debate. The human principal retains final authority through the "Chancela" (Portuguese for "chancellor's seal"), but the ELO rating system ensures that well-reasoned proposals accumulate credibility over time.

This is not a toy. Proposals can modify the agent's own behavioral rules, tool access, and prompt configuration. The governance system is how the workspace self-evolves.

## The 7 Columns

```mermaid
graph LR
    D["Draft"] --> S["Submitted"]
    S --> DB["Debating"]
    DB --> CC["Chancela"]
    CC --> AP["Approved"]
    CC --> VT["Vetoed"]
    AP --> PR["Promoted"]
    VT --> ARCH["Archived"]

    style D fill:#3e4451,stroke:#5c6370,color:#abb2bf
    style S fill:#2c6fbb,stroke:#3d85c6,color:#fff
    style DB fill:#d19a66,stroke:#e5c07b,color:#282c34
    style CC fill:#e06c75,stroke:#e06c75,color:#fff
    style AP fill:#61afef,stroke:#56b6c2,color:#282c34
    style VT fill:#be5046,stroke:#e06c75,color:#fff
    style PR fill:#98c379,stroke:#56b6c2,color:#282c34
```

| # | Column | ID | Purpose |
|---|---|---|---|
| 1 | Draft | `draft` | Initial proposal state. Created by any user or agent. Not yet visible to congress. |
| 2 | Submitted | `submitted` | Proposal is ready for review. Added to the congress queue. `submitted_at` timestamp recorded. |
| 3 | Debating | `debating` | Active adversarial debate rounds. ELO rating updates with each round. |
| 4 | Chancela | `awaiting_chancela` | Passed debate. Awaiting human approval or veto. Visually highlighted with red glow. |
| 5 | Approved | `congress_approved` | Congress has approved the proposal. Awaiting final Chancela. |
| 6 | Vetoed | `vetoed` | Rejected by Chancela or during congress. Terminal state. |
| 7 | Promoted | `promoted` | Fully approved and promoted. The proposal is now active policy. |

The `archived` status exists in the backend enum but has no dedicated column in the UI -- archived proposals are hidden from the board.

## Proposal Lifecycle

```mermaid
stateDiagram-v2
    [*] --> Draft: create_proposal()
    Draft --> Submitted: update_status(SUBMITTED)
    Submitted --> Debating: update_status(DEBATING)
    Debating --> Debating: record_debate_round()
    Debating --> CongressApproved: congress close(resolutions)
    Debating --> Vetoed: congress close(resolutions)
    Submitted --> CongressApproved: congress close(resolutions)
    CongressApproved --> AwaitingChancela: update_status(AWAITING_CHANCELA)
    AwaitingChancela --> Promoted: chancela_proposal(approved=True)
    AwaitingChancela --> Vetoed: chancela_proposal(approved=False)
    CongressApproved --> Vetoed: chancela_proposal(approved=False)
    Draft --> Archived: update_status(ARCHIVED)
    Vetoed --> Archived: update_status(ARCHIVED)
```

### Step 1: Creation

Any authenticated user (or agent via API token) creates a proposal with:

- **Category**: What kind of change (skill, workflow, rule, hook, integration, tool, mcp, model_config, harness_config, prompt)
- **Name**: Human-readable title
- **Content**: The actual proposal detail
- **Rationale**: Why this change is needed
- **Origin**: Where the idea came from (failure_observation, dead_end_analysis, performance_insight, reflection, human_directive, congress_debate)
- **Failure context** (optional): What went wrong that prompted this
- **Current artifact** (optional): The existing artifact being proposed for change

### Step 2: Submission

The proposer (or an admin) moves the proposal to `submitted`. This records `submitted_at` and makes it visible to the congress system.

### Step 3: Debate

Proposals enter adversarial debate rounds. Each round:

1. The proposal is pitted against an opponent (another proposal or a baseline)
2. A judge (typically the local model, but extensible) evaluates which is stronger
3. ELO ratings are updated using the standard chess formula:

```
expected = 1 / (1 + 10^((opponent_elo - proposal_elo) / 400))
actual = 1.0 if won, 0.0 if lost
proposal_elo += K * (actual - expected)
```

Where `K = 32` (standard ELO coefficient).

Each debate round is logged with timestamp, outcome, ELO after, opponent ELO, reason, and judge. The `debate_log` JSON column stores the full history.

### Step 4: Congress

The `CentralCommittee` convenes a congress session:

1. **Convene**: Gather all proposals in `submitted` or `debating` status. Record which agents are present.
2. **Deliberate**: Agents discuss and vote on proposals (resolution data stored in congress session).
3. **Close**: Congress records resolutions and marks the session as concluded.

Congress can approve or veto proposals. Approved proposals move to `congress_approved`; vetoed ones move to `vetoed`.

### Step 5: Chancela

The human principal reviews proposals that passed congress. This is the ultimate authority gate:

- **Approve**: Proposal moves to `promoted`. It becomes active policy.
- **Veto**: Proposal moves to `vetoed`. It is rejected.

The `chancela_proposal` method records `approved_at`, `approved_by`, and `promoted_at` timestamps.

### Step 6: Promotion

Promoted proposals are the living policy of the workspace. Their content can be:

- New MCP tool configurations
- Modified agent rules or prompts
- Updated model routing policies
- New skills or workflows
- Changed governance parameters

## Proposal Categories

| Category | ID | Typical Content |
|---|---|---|
| Skill | `skill` | New reusable skill definition |
| Workflow | `workflow` | Multi-step process improvement |
| Rule | `rule` | Behavioral constraint or directive |
| Hook | `hook` | PreToolUse/PostToolUse enforcement |
| Integration | `integration` | External service connection |
| Tool | `tool` | New agent tool or modification |
| MCP | `mcp` | MCP server configuration |
| Model Config | `model_config` | Endpoint, routing, or fallback changes |
| Harness Config | `harness_config` | Dashboard or system-level settings |
| Prompt | `prompt` | System prompt modifications |

## Proposal Origins

| Origin | ID | When Used |
|---|---|---|
| Failure Observation | `failure_observation` | Agent observed a failure and proposes a fix |
| Dead End Analysis | `dead_end_analysis` | Agent hit a dead end and proposes an alternative path |
| Performance Insight | `performance_insight` | Agent identified a performance improvement |
| Reflection | `reflection` | Agent self-reflects and proposes behavioral changes |
| Human Directive | `human_directive` | Human explicitly requested a change |
| Congress Debate | `congress_debate` | Emerged from congress discussion |

## ELO Rating System

Each proposal starts with an ELO of 1200 (standard chess baseline). Debate rounds adjust this rating:

| ELO Range | Interpretation |
|---|---|
| < 1000 | Weak proposal, consistently losing debates |
| 1000-1200 | Below average, needs significant improvement |
| 1200 | Baseline (starting value) |
| 1200-1400 | Above average, winning more than losing |
| 1400-1600 | Strong proposal, well-reasoned |
| > 1600 | Exceptional proposal, dominant in debates |

The ELO system is borrowed directly from the unit distance research project (unit-distance-problem), where hypothesis evaluation used the same adversarial calibration approach. In the governance context, it provides a quantitative signal for the Chancela decision -- proposals with higher ELO ratings have demonstrated their quality through adversarial testing.

## Database Models

Three SQLAlchemy models support the governance system:

### GovernanceProposal

```python
class GovernanceProposal(TimestampMixin, Base):
    __tablename__ = "governance_proposals"

    id              = Column(String(50), primary_key)
    category        = Column(String(50), nullable=False)
    name            = Column(String(200), nullable=False)
    content         = Column(Text, nullable=False)
    rationale       = Column(Text, nullable=False)
    proposed_by     = Column(String(100), nullable=False)
    origin          = Column(String(50), nullable=False)
    status          = Column(String(50), default="draft")
    elo_rating      = Column(Integer, default=1200)
    debate_log      = Column(JSON, default=list)
    failure_context = Column(Text, default="")
    current_artifact= Column(Text, default="")
    congress_votes  = Column(JSON, default=dict)
    strategy_notes  = Column(Text, default="")
    submitted_at    = Column(DateTime, nullable=True)
    approved_at     = Column(DateTime, nullable=True)
    approved_by     = Column(String(100), nullable=True)
    promoted_at     = Column(DateTime, nullable=True)
```

### CongressSession

```python
class CongressSession(TimestampMixin, Base):
    __tablename__ = "congress_sessions"

    id                   = Column(String(50), primary_key)
    convened_at          = Column(DateTime, default=utcnow_naive)
    proposals_discussed  = Column(JSON, default=list)
    agents_present       = Column(JSON, default=list)
    resolutions          = Column(JSON, default=list)
    closed_at            = Column(DateTime, nullable=True)
    status               = Column(String(50), default="in_session")
```

### QuinquennialPlan

```python
class QuinquennialPlan(TimestampMixin, Base):
    __tablename__ = "quinquennial_plans"

    id                = Column(String(50), primary_key)
    title             = Column(String(200), nullable=False)
    objectives        = Column(JSON, default=list)
    kpis              = Column(JSON, default=dict)
    duration_days     = Column(Integer, nullable=True)
    duration_rationale= Column(Text, default="")
    phases            = Column(JSON, default=list)
    status            = Column(String(50), default="proposed")
    proposed_by       = Column(String(100), default="")
    approved_by       = Column(String(100), nullable=True)
    started_at        = Column(DateTime, nullable=True)
    completed_at      = Column(DateTime, nullable=True)
```

The QuinquennialPlan represents long-term strategic planning -- titled after the "Five Year Plans" of governance, adapted for the AI workspace context.

## API Endpoints

All endpoints are mounted under `/api/governance` and require authentication.

| Method | Endpoint | Purpose |
|---|---|---|
| `GET` | `/api/governance/proposals` | List all proposals (optional `?status=` filter) |
| `POST` | `/api/governance/proposals` | Create a new proposal |
| `GET` | `/api/governance/proposals/{id}` | Get proposal details + debate log |
| `POST` | `/api/governance/proposals/{id}/status` | Update proposal status |
| `POST` | `/api/governance/proposals/{id}/chancela` | Human approval/veto |
| `POST` | `/api/governance/proposals/{id}/debate` | Record a debate round |
| `POST` | `/api/governance/congress/convene` | Convene a congress session |
| `POST` | `/api/governance/congress/{id}/close` | Close congress with resolutions |
| `GET` | `/api/governance/plans/active` | Get the active strategic plan |
| `POST` | `/api/governance/plans` | Propose a new strategic plan |

## Frontend: The Kanban UI

The kanban board is rendered in `static/js/governance.js` as a drag-and-drop interface:

### Column Rendering

Each of the 7 columns is rendered as a vertical strip with:

- A header showing the column title and card count
- A dropzone area accepting draggable proposal cards
- Visual emphasis on the Chancela column (red glow border)

### Proposal Cards

Each card displays:

- Proposal name (bold)
- Category badge
- ELO rating
- Proposed by (user/agent name)
- Origin indicator
- Status-specific styling

Cards are draggable (`draggable=true`) and support standard HTML5 drag-and-drop between columns. When a card is dropped in a new column, `updateProposalStatus()` calls the API to persist the status change.

### Interaction Flow

1. User clicks the "Governance" sidebar button
2. Chat and other views are hidden; governance view is displayed
3. `fetchProposals()` loads all proposals from `/api/governance/proposals`
4. `renderCards()` distributes proposals into their respective columns
5. User can drag cards between columns to update status
6. User can click a card to view details, debate log, and congress votes

### Styling

The kanban board uses the dashboard's CSS variable system:

| Variable | Purpose |
|---|---|
| `--panel` | Column background (`#1e2227`) |
| `--border` | Column/card borders (`#3e4451`) |
| `--bg` | Card background (`#282c34`) |
| `--red` | Chancela column highlight (`#e06c75`) |

The Chancela column has special visual treatment: a red-tinted border and a `box-shadow: 0 0 15px rgba(224, 108, 117, 0.2)` glow, signaling that proposals in this column require urgent human attention.

## Agent Interaction

Agents interact with the governance system through the tool system. The `do_manage_tasks` function in `tool_implementations.py` can:

1. Create proposals when the agent identifies a needed change
2. Record debate rounds as the agent defends or challenges proposals
3. Query proposal status to inform decision-making

Agents cannot invoke the Chancela (human-only), but they can:
- Submit proposals for human review
- Participate in congress debates
- Propose strategic plans through the `CentralCommittee`

## Cross-References

- [[co-fita-odysseus]] -- The parent dashboard hosting the governance system
- [[co-fita-mcp-servers]] -- MCP servers whose configurations are governed
- [[co-fita-harness]] -- The parent harness with full context
- [[fitalabs-infra]] -- Infrastructure and deployment

## Implementation Files

| File | Lines | Purpose |
|---|---|---|
| `src/governance_engine.py` | ~209 | Core engine: GovernanceEngine + CentralCommittee |
| `routes/governance_routes.py` | ~137 | FastAPI route layer |
| `core/database.py` | (lines 2357-2407) | 3 SQLAlchemy model definitions |
| `static/js/governance.js` | ~120+ | Kanban frontend (drag-and-drop) |

## Design Notes

**Human authority is absolute**: The Chancela step cannot be bypassed by agents or API calls. Even if a proposal achieves the highest ELO rating and passes congress unanimously, the human principal must explicitly approve it. This is a hard safety boundary.

**Debate is quantitative, not just qualitative**: The ELO system provides a numerical signal that accumulates across multiple debate rounds. A proposal with ELO 1500 has demonstrated superiority over many opponents, while a proposal at 1000 has consistently lost. This removes purely subjective judgment from the intermediate stages.

**The system is recursive**: Proposals can modify the governance system itself. A proposal to change the ELO K-factor, add new categories, or modify the congress voting rules would flow through the same pipeline. The Chancela gate ensures the human approves any meta-level changes.

**Congress is multi-agent**: The `agents_present` field in CongressSession records which agents participated. This enables analysis of voting patterns and agent alignment over time.

> "Protocols are dialectical instruments -- they exist to be challenged and refined."
