Hmbown/CodeWhale · error · anyhow::Error

continual harness is full ({MAX_ENTRIES} entries); remove an

Error message

continual harness is full ({MAX_ENTRIES} entries); remove an obsolete entry before refining again

What it means

Thrown by continual_harness::refine when the workspace harness state already holds MAX_ENTRIES (24) entries and the new refinement is not an exact duplicate. The ledger is intentionally bounded; an identical (kind, title, content) refinement dedupes and returns the existing entry even at capacity, so only genuinely new entries are refused.

Source

Thrown at crates/tui/src/continual_harness.rs:111

pub fn refine(workspace: &Path, refinement: HarnessRefinement) -> Result<HarnessEntry> {
    let refinement = validate_refinement(refinement)?;
    let path = state_path_for_write(workspace)?;
    with_write_lock(&path, || {
        // Reload *inside* the cross-process writer lock. Atomic publication
        // protects readers from torn JSON, while this transaction prevents
        // two approved refinements from both deriving changes from a stale
        // snapshot and dropping one another's entry.
        let mut state = load_state(&path)?;

        if let Some(existing) = state.entries.iter().find(|entry| {
            entry.kind == refinement.kind
                && entry.title == refinement.title
                && entry.content == refinement.content
        }) {
            return Ok(existing.clone());
        }
        if state.entries.len() >= MAX_ENTRIES {
            bail!(
                "continual harness is full ({MAX_ENTRIES} entries); remove an obsolete entry before refining again"
            );
        }

        let entry = HarnessEntry {
            id: format!("h_{}", Uuid::new_v4().simple()),
            kind: refinement.kind,
            title: refinement.title,
            content: refinement.content,
            evidence: refinement.evidence,
        };
        state.schema_version = SCHEMA_VERSION;
        state.entries.push(entry.clone());
        save_state(&path, &state)?;
        // Journalled after the state is durable: a logged edit that never
        // landed would be worse than an unlogged one.
        append_journal(&path, "refine", &entry)?;
        Ok(entry)

View on GitHub (pinned to 0c42157ee5)

Solutions

  1. Remove an obsolete entry first: call continual_harness::remove(workspace, id) with the entry's id
  2. List entries via overview(workspace) to find the least valuable id to drop
  3. Consolidate overlapping refinements into one entry instead of adding more

Example fix

// before: refine on a full ledger
let entry = continual_harness::refine(&workspace, refinement)?;

// after: make room first
let overview = continual_harness::overview(&workspace)?;
let obsolete = overview.entries.iter().min_by_key(|e| (e.kind.as_str().len(), e.title.clone()));
if let Some(obsolete) = obsolete {
    continual_harness::remove(&workspace, &obsolete.id)?;
}
let entry = continual_harness::refine(&workspace, refinement)?;
Defensive patterns

Strategy: validation

Validate before calling

// Check capacity and dedupe before refining:
let overview = continual_harness::overview(&workspace)?;
let duplicate = overview.entries.iter().any(|e|
    e.kind == refinement.kind && e.title == refinement.title && e.content == refinement.content
);
if !duplicate && overview.entries.len() >= 24 {
    // prompt the caller to remove an obsolete entry by id first
    let removable = pick_obsolete_entry(&overview.entries);
    continual_harness::remove(&workspace, &removable.id)?;
}
let entry = continual_harness::refine(&workspace, refinement)?;

Try / catch

match continual_harness::refine(&workspace, refinement) {
    Ok(entry) => { /* ... */ }
    Err(error) if error.to_string().contains("continual harness is full") => {
        // list entries, let the user pick one to remove, then retry once
    }
    Err(error) => return Err(error),
}

Prevention

When it happens

Trigger: Calling the harness refine tool (crate::continual_harness::refine) on a workspace whose state file already has 24 entries. The check runs inside the cross-process write lock after reloading state, so concurrent refines cannot slip past it.

Common situations: A long-lived project accumulating prompt notes, sub-agent specs, and skill hints; the model attempting another refinement after the ledger filled up.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20). Data as JSON: /api/errors/6ad92f0ae1b3a2dd. Report an issue: GitHub.