---
name: "Add a debug MCP tool to dump the in-memory CRDT state for inspection"
---

# Story 515: Add a debug MCP tool to dump the in-memory CRDT state for inspection

## User Story

**Note:** content stuffed into user_story per bug 509 workaround.

---

## Context

When diagnosing CRDT/state issues today, we had no way to look at the **in-memory** CRDT state directly. The closest available views were:

- `get_pipeline_status` — gives a summarised pipeline-shaped view (active/backlog/done) but hides the raw item structure, the index map, the lamport clock state, etc.
- Querying `crdt_ops` directly via sqlite — gives the *persisted* state, which can diverge from the in-memory state (we saw this with bug 511, where post-restart writes use reset seq counters)
- `read_item(story_id)` in `crdt_state.rs` — exists, returns a `PipelineItemView`, but is not exposed via MCP or HTTP

The result: every time I needed to check the CRDT state, I was either inferring it from `get_pipeline_status` (lossy) or querying the persisted ops (lagging the in-memory state). Neither gave me the ground truth.

## Real user story

As a developer debugging huskies state issues, I want an MCP tool (or HTTP debug endpoint) that returns a structured dump of the in-memory CRDT state, so I can see exactly what the running server thinks is true without inferring from summaries.

## Suggested API

- Tool name: `mcp__huskies__dump_crdt`
- Args: optional `story_id` filter (single story) or no args (dump everything)
- Returns: JSON with one entry per item containing: `story_id`, all field values (`stage`, `name`, `agent`, `retry_count`, `blocked`, `depends_on`), the CRDT path/index bytes (for cross-referencing with `crdt_ops`), the local lamport seq counter, and a flag indicating whether the item is `is_deleted`
- Returns metadata: total item count, current local seq counter value, count of pending ops in `persist_tx` channel (if observable)

## Observed 2026-04-09

This story would have saved us significant debugging time. Specific examples:

- When 478 was missing from `get_pipeline_status` after the manual sqlite insert, we had to infer "the API reads from in-memory CRDT, not from pipeline_items" by looking at source code. A `dump_crdt 478_…` call would have returned "not found" immediately, confirming the same conclusion.
- When 503 was showing at stage=merge in the API but only had a creation op at stage=1_backlog in `crdt_ops`, we had to manually search for content-indexed update ops to figure out where the post-restart updates went. A dump tool showing the current in-memory state vs the persisted op count would have made the divergence obvious.

## Acceptance Criteria

- [ ] New MCP tool `dump_crdt` is registered and callable
- [ ] With no args, returns all items in the in-memory CRDT as a structured JSON list
- [ ] With a story_id arg, returns just that one item (or null if not found)
- [ ] Each item entry includes: story_id, stage, name, agent, retry_count, blocked, depends_on, content_index (hex), is_deleted
- [ ] Returns top-level metadata: total_items, max_local_seq, pending_persist_ops_count (if available), in_memory_state_loaded (bool)
- [ ] Tool description is clear that this is a debug tool, not for normal pipeline introspection (those should use get_pipeline_status)
- [ ] Optional: also expose via HTTP at `/debug/crdt` for browser inspection
- [ ] Documented in README.md under a 'debugging' section

## Out of Scope

- TBD
